summaryrefslogtreecommitdiffstats
path: root/extensions/BMO
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/BMO')
-rw-r--r--extensions/BMO/Config.pm48
-rw-r--r--extensions/BMO/Extension.pm1561
-rwxr-xr-xextensions/BMO/bin/bug_1022707.pl50
-rwxr-xr-xextensions/BMO/bin/migrate-github-pull-requests.pl90
-rw-r--r--extensions/BMO/lib/Constants.pm33
-rw-r--r--extensions/BMO/lib/Data.pm242
-rw-r--r--extensions/BMO/lib/FakeBug.pm42
-rw-r--r--extensions/BMO/lib/Reports/EmailQueue.pm84
-rw-r--r--extensions/BMO/lib/Reports/Groups.pm243
-rw-r--r--extensions/BMO/lib/Reports/ProductSecurity.pm67
-rw-r--r--extensions/BMO/lib/Reports/ReleaseTracking.pm409
-rw-r--r--extensions/BMO/lib/Reports/Triage.pm217
-rw-r--r--extensions/BMO/lib/Reports/UserActivity.pm327
-rw-r--r--extensions/BMO/lib/Util.pm90
-rw-r--r--extensions/BMO/lib/WebService.pm200
-rw-r--r--extensions/BMO/t/bug_format_comment.t84
-rw-r--r--extensions/BMO/template/en/default/account/create.html.tmpl178
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-automative.txt.tmpl52
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-creative.txt.tmpl39
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-dev-engagement-event.txt.tmpl84
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-doc.txt.tmpl20
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-employee-incident.txt.tmpl57
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-finance.txt.tmpl35
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-fxos-betaprogram.txt.tmpl24
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-fxos-feature.txt.tmpl24
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-fxos-mcts-waiver.txt.tmpl36
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-fxos-partner.txt.tmpl23
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-fxos-preload-app.txt.tmpl28
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-ipp.txt.tmpl30
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-legal.txt.tmpl39
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-mdn.txt.tmpl66
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-mobile-compat.txt.tmpl33
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-mozlist.txt.tmpl44
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-mozpr.txt.tmpl130
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-privacy-data.txt.tmpl30
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-recoverykey.txt.tmpl28
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-swag.txt.tmpl50
-rw-r--r--extensions/BMO/template/en/default/bug/create/comment-user-engagement.txt.tmpl36
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-automative.html.tmpl276
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-creative.html.tmpl259
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-dev-engagement-event.html.tmpl537
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-doc.html.tmpl222
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-employee-incident.html.tmpl11
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-finance.html.tmpl257
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-fxos-betaprogram.html.tmpl180
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-fxos-feature.html.tmpl181
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-fxos-mcts-waiver.html.tmpl208
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-fxos-partner.html.tmpl239
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-fxos-preload-app.html.tmpl185
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-ipp.html.tmpl183
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-itrequest.html.tmpl238
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-legal.html.tmpl226
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-mdn.html.tmpl279
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-mobile-compat.html.tmpl201
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-mozlist.html.tmpl177
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-mozpr.html.tmpl683
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-poweredby.html.tmpl87
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-presentation.html.tmpl11
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-privacy-data.html.tmpl219
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-recoverykey.html.tmpl70
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-swag.html.tmpl903
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-trademark.html.tmpl87
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-user-engagement.html.tmpl219
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-web-bounty.html.tmpl142
-rw-r--r--extensions/BMO/template/en/default/bug/create/create-winqual.html.tmpl831
-rw-r--r--extensions/BMO/template/en/default/bug/create/created-fxos-betaprogram.html.tmpl30
-rw-r--r--extensions/BMO/template/en/default/bug/create/custom_forms.none.tmpl173
-rw-r--r--extensions/BMO/template/en/default/bug/create/user-message.html.tmpl49
-rw-r--r--extensions/BMO/template/en/default/email/bugmail.html.tmpl204
-rw-r--r--extensions/BMO/template/en/default/email/bugmail.txt.tmpl92
-rw-r--r--extensions/BMO/template/en/default/global/choose-product.html.tmpl228
-rw-r--r--extensions/BMO/template/en/default/global/prod-comp-search.html.tmpl43
-rw-r--r--extensions/BMO/template/en/default/global/redirect.html.tmpl25
-rw-r--r--extensions/BMO/template/en/default/hook/admin/params/editparams-current_panel.html.tmpl13
-rw-r--r--extensions/BMO/template/en/default/hook/attachment/createformcontents-mimetypes.html.tmpl2
-rw-r--r--extensions/BMO/template/en/default/hook/attachment/createformcontents-patch_notes.html.tmpl1
-rw-r--r--extensions/BMO/template/en/default/hook/bug/comments-a_comment-end.html.tmpl19
-rw-r--r--extensions/BMO/template/en/default/hook/bug/comments-aftercomments.html.tmpl69
-rw-r--r--extensions/BMO/template/en/default/hook/bug/comments-comment_banner.html.tmpl13
-rw-r--r--extensions/BMO/template/en/default/hook/bug/create/create-after_custom_fields.html.tmpl30
-rw-r--r--extensions/BMO/template/en/default/hook/bug/create/create-custom_field.html.tmpl13
-rw-r--r--extensions/BMO/template/en/default/hook/bug/create/create-end.html.tmpl33
-rw-r--r--extensions/BMO/template/en/default/hook/bug/create/create-form.html.tmpl47
-rw-r--r--extensions/BMO/template/en/default/hook/bug/edit-after_importance.html.tmpl76
-rw-r--r--extensions/BMO/template/en/default/hook/bug/edit-before_restrict_visibility.html.tmpl25
-rw-r--r--extensions/BMO/template/en/default/hook/bug/field-help-end.none.tmpl96
-rw-r--r--extensions/BMO/template/en/default/hook/bug/process/header-title.html.tmpl9
-rw-r--r--extensions/BMO/template/en/default/hook/bug/show-header-end.html.tmpl18
-rw-r--r--extensions/BMO/template/en/default/hook/global/field-descs-end.none.tmpl12
-rw-r--r--extensions/BMO/template/en/default/hook/global/footer-end.html.tmpl11
-rw-r--r--extensions/BMO/template/en/default/hook/global/header-additional_header.html.tmpl54
-rw-r--r--extensions/BMO/template/en/default/hook/global/header-start.html.tmpl41
-rw-r--r--extensions/BMO/template/en/default/hook/global/messages-messages.html.tmpl5
-rw-r--r--extensions/BMO/template/en/default/hook/global/setting-descs-settings.none.tmpl14
-rw-r--r--extensions/BMO/template/en/default/hook/global/user-error-auth_failure_object.html.tmpl17
-rw-r--r--extensions/BMO/template/en/default/hook/global/user-error-error_message.html.tmpl26
-rw-r--r--extensions/BMO/template/en/default/hook/global/user-error-errors.html.tmpl40
-rw-r--r--extensions/BMO/template/en/default/hook/global/user-error.html.tmpl/auth_failure/permissions.html.tmpl29
-rw-r--r--extensions/BMO/template/en/default/hook/global/variables-end.none.tmpl3
-rw-r--r--extensions/BMO/template/en/default/hook/index-additional_links.html.tmpl18
-rw-r--r--extensions/BMO/template/en/default/hook/index-intro.html.tmpl2
-rw-r--r--extensions/BMO/template/en/default/hook/list/list-links.html.tmpl15
-rw-r--r--extensions/BMO/template/en/default/hook/list/table-before_table.html.tmpl9
-rw-r--r--extensions/BMO/template/en/default/hook/pages/fields-resolution.html.tmpl13
-rw-r--r--extensions/BMO/template/en/default/hook/reports/menu-end.html.tmpl59
-rw-r--r--extensions/BMO/template/en/default/list/list.microsummary.tmpl29
-rw-r--r--extensions/BMO/template/en/default/list/server-push.html.tmpl52
-rw-r--r--extensions/BMO/template/en/default/pages/bug-writing.html.tmpl11
-rw-r--r--extensions/BMO/template/en/default/pages/custom_forms.html.tmpl40
-rw-r--r--extensions/BMO/template/en/default/pages/email_queue.html.tmpl67
-rw-r--r--extensions/BMO/template/en/default/pages/etiquette.html.tmpl146
-rw-r--r--extensions/BMO/template/en/default/pages/get_help.html.tmpl42
-rw-r--r--extensions/BMO/template/en/default/pages/get_permissions.html.tmpl44
-rw-r--r--extensions/BMO/template/en/default/pages/group_admins.html.tmpl54
-rw-r--r--extensions/BMO/template/en/default/pages/group_members.html.tmpl97
-rw-r--r--extensions/BMO/template/en/default/pages/group_members.json.tmpl32
-rw-r--r--extensions/BMO/template/en/default/pages/group_membership.html.tmpl75
-rw-r--r--extensions/BMO/template/en/default/pages/group_membership.txt.tmpl16
-rw-r--r--extensions/BMO/template/en/default/pages/product_security_report.html.tmpl60
-rw-r--r--extensions/BMO/template/en/default/pages/query_database.html.tmpl47
-rw-r--r--extensions/BMO/template/en/default/pages/release_tracking_report.html.tmpl103
-rw-r--r--extensions/BMO/template/en/default/pages/triage_reports.html.tmpl199
-rw-r--r--extensions/BMO/template/en/default/pages/upgrade-3.6.html.tmpl304
-rw-r--r--extensions/BMO/template/en/default/pages/user_activity.html.tmpl230
-rw-r--r--extensions/BMO/template/en/default/search/search-plugin.xml.tmpl17
-rw-r--r--extensions/BMO/web/core.pngbin0 -> 7497 bytes
-rw-r--r--extensions/BMO/web/images/advanced.pngbin0 -> 720 bytes
-rw-r--r--extensions/BMO/web/images/background.pngbin0 -> 1695 bytes
-rw-r--r--extensions/BMO/web/images/bugzilla.pngbin0 -> 1242 bytes
-rw-r--r--extensions/BMO/web/images/creative.pngbin0 -> 245022 bytes
-rw-r--r--extensions/BMO/web/images/favicon.icobin0 -> 1150 bytes
-rw-r--r--extensions/BMO/web/images/groups/bugzilla-approvers.pngbin0 -> 829 bytes
-rw-r--r--extensions/BMO/web/images/groups/calendar-drivers.pngbin0 -> 744 bytes
-rw-r--r--extensions/BMO/web/images/guided.pngbin0 -> 1045 bytes
-rw-r--r--extensions/BMO/web/images/mozchomp.gifbin0 -> 89485 bytes
-rw-r--r--extensions/BMO/web/images/mozilla-tab.pngbin0 -> 7535 bytes
-rw-r--r--extensions/BMO/web/images/notice.pngbin0 -> 6654 bytes
-rw-r--r--extensions/BMO/web/images/presshat.pngbin0 -> 23450 bytes
-rw-r--r--extensions/BMO/web/images/sign_warning.pngbin0 -> 1776 bytes
-rw-r--r--extensions/BMO/web/images/stop-sign.gifbin0 -> 3227 bytes
-rw-r--r--extensions/BMO/web/images/throbber.gifbin0 -> 723 bytes
-rw-r--r--extensions/BMO/web/images/user-engagement.pngbin0 -> 25818 bytes
-rw-r--r--extensions/BMO/web/js/edit_bug.js41
-rw-r--r--extensions/BMO/web/js/edituser_menu.js33
-rw-r--r--extensions/BMO/web/js/form_validate.js41
-rw-r--r--extensions/BMO/web/js/release_tracking_report.js203
-rw-r--r--extensions/BMO/web/js/sorttable.js709
-rw-r--r--extensions/BMO/web/js/swag.js60
-rw-r--r--extensions/BMO/web/js/triage_reports.js83
-rw-r--r--extensions/BMO/web/js/webtrends.js213
-rw-r--r--extensions/BMO/web/producticons/component.pngbin0 -> 7497 bytes
-rw-r--r--extensions/BMO/web/producticons/dino.pngbin0 -> 3375 bytes
-rw-r--r--extensions/BMO/web/producticons/firefox.pngbin0 -> 7720 bytes
-rw-r--r--extensions/BMO/web/producticons/firefox_android.pngbin0 -> 15997 bytes
-rw-r--r--extensions/BMO/web/producticons/firefox_os.pngbin0 -> 18928 bytes
-rw-r--r--extensions/BMO/web/producticons/input.pngbin0 -> 8333 bytes
-rw-r--r--extensions/BMO/web/producticons/localization.pngbin0 -> 6914 bytes
-rw-r--r--extensions/BMO/web/producticons/marketplace.pngbin0 -> 7412 bytes
-rw-r--r--extensions/BMO/web/producticons/other.pngbin0 -> 6654 bytes
-rw-r--r--extensions/BMO/web/producticons/seamonkey.pngbin0 -> 5255 bytes
-rw-r--r--extensions/BMO/web/producticons/sync.pngbin0 -> 8896 bytes
-rw-r--r--extensions/BMO/web/producticons/thunderbird.pngbin0 -> 9939 bytes
-rw-r--r--extensions/BMO/web/producticons/webmaker.pngbin0 -> 59095 bytes
-rw-r--r--extensions/BMO/web/styles/choose_product.css16
-rw-r--r--extensions/BMO/web/styles/create_account.css62
-rw-r--r--extensions/BMO/web/styles/edit_bug.css49
-rw-r--r--extensions/BMO/web/styles/reports.css75
-rw-r--r--extensions/BMO/web/styles/triage_reports.css23
-rw-r--r--extensions/BMO/web/yui-history-iframe.txt0
169 files changed, 16933 insertions, 0 deletions
diff --git a/extensions/BMO/Config.pm b/extensions/BMO/Config.pm
new file mode 100644
index 000000000..93445f576
--- /dev/null
+++ b/extensions/BMO/Config.pm
@@ -0,0 +1,48 @@
+# -*- 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 BMO Bugzilla Extension.
+#
+# The Initial Developer of the Original Code is Gervase Markham
+# Portions created by the Initial Developer are Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Gervase Markham <gerv@gerv.net>
+
+package Bugzilla::Extension::BMO;
+use strict;
+
+use constant NAME => 'BMO';
+
+use constant REQUIRED_MODULES => [
+ {
+ package => 'Tie-IxHash',
+ module => 'Tie::IxHash',
+ version => 0
+ },
+ {
+ package => 'Sys-Syslog',
+ module => 'Sys::Syslog',
+ version => 0
+ },
+ {
+ package => 'File-MimeInfo',
+ module => 'File::MimeInfo::Magic',
+ version => '0'
+ },
+];
+
+use constant OPTIONAL_MODULES => [
+];
+
+__PACKAGE__->NAME;
diff --git a/extensions/BMO/Extension.pm b/extensions/BMO/Extension.pm
new file mode 100644
index 000000000..c28238197
--- /dev/null
+++ b/extensions/BMO/Extension.pm
@@ -0,0 +1,1561 @@
+# -*- 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 BMO Bugzilla Extension.
+#
+# The Initial Developer of the Original Code is Gervase Markham.
+# Portions created by the Initial Developer are Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Gervase Markham <gerv@gerv.net>
+# David Lawrence <dkl@mozilla.com>
+# Byron Jones <glob@mozilla.com>
+
+package Bugzilla::Extension::BMO;
+use strict;
+use base qw(Bugzilla::Extension);
+
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Field;
+use Bugzilla::Group;
+use Bugzilla::Mailer;
+use Bugzilla::Product;
+use Bugzilla::Status;
+use Bugzilla::Token;
+use Bugzilla::Install::Filesystem;
+use Bugzilla::User;
+use Bugzilla::User::Setting;
+use Bugzilla::Util;
+
+use Date::Parse;
+use DateTime;
+use Encode qw(find_encoding encode_utf8);
+use File::MimeInfo::Magic;
+use List::MoreUtils qw(natatime);
+use Scalar::Util qw(blessed);
+use Sys::Syslog qw(:DEFAULT setlogsock);
+
+use Bugzilla::Extension::BMO::Constants;
+use Bugzilla::Extension::BMO::FakeBug;
+use Bugzilla::Extension::BMO::Data;
+
+our $VERSION = '0.1';
+
+#
+# Monkey-patched methods
+#
+
+BEGIN {
+ *Bugzilla::Bug::last_closed_date = \&_last_closed_date;
+ *Bugzilla::Product::default_security_group = \&_default_security_group;
+ *Bugzilla::Product::default_security_group_obj = \&_default_security_group_obj;
+ *Bugzilla::Product::group_always_settable = \&_group_always_settable;
+ *Bugzilla::check_default_product_security_group = \&_check_default_product_security_group;
+}
+
+sub template_before_process {
+ my ($self, $args) = @_;
+ my $file = $args->{'file'};
+ my $vars = $args->{'vars'};
+
+ $vars->{'cf_hidden_in_product'} = \&cf_hidden_in_product;
+
+ if ($file =~ /^list\/list/) {
+ # Purpose: enable correct sorting of list table
+ # Matched to changes in list/table.html.tmpl
+ my %db_order_column_name_map = (
+ 'map_components.name' => 'component',
+ 'map_products.name' => 'product',
+ 'map_reporter.login_name' => 'reporter',
+ 'map_assigned_to.login_name' => 'assigned_to',
+ 'delta_ts' => 'opendate',
+ 'creation_ts' => 'changeddate',
+ );
+
+ my @orderstrings = split(/,\s*/, $vars->{'order'});
+
+ # contains field names of the columns being used to sort the table.
+ my @order_columns;
+ foreach my $o (@orderstrings) {
+ $o =~ s/bugs.//;
+ $o = $db_order_column_name_map{$o} if
+ grep($_ eq $o, keys(%db_order_column_name_map));
+ next if (grep($_ eq $o, @order_columns));
+ push(@order_columns, $o);
+ }
+
+ $vars->{'order_columns'} = \@order_columns;
+
+ # fields that have a custom sortkey. (So they are correctly sorted
+ # when using js)
+ my @sortkey_fields = qw(bug_status resolution bug_severity priority
+ rep_platform op_sys);
+
+ my %columns_sortkey;
+ foreach my $field (@sortkey_fields) {
+ $columns_sortkey{$field} = _get_field_values_sort_key($field);
+ }
+ $columns_sortkey{'target_milestone'} = _get_field_values_sort_key('milestones');
+
+ $vars->{'columns_sortkey'} = \%columns_sortkey;
+ }
+ elsif ($file =~ /^bug\/create\/create[\.-](.*)/) {
+ my $format = $1;
+ if (!$vars->{'cloned_bug_id'}) {
+ # Allow status whiteboard values to be bookmarked
+ $vars->{'status_whiteboard'} =
+ Bugzilla->cgi->param('status_whiteboard') || "";
+ }
+
+ # Purpose: for pretty product chooser
+ $vars->{'format'} = Bugzilla->cgi->param('format');
+
+ if ($format eq 'doc.html.tmpl') {
+ my $versions = Bugzilla::Product->new({ name => 'Core' })->versions;
+ $vars->{'versions'} = [ reverse @$versions ];
+ }
+ }
+
+
+ if ($file =~ /^list\/list/ || $file =~ /^bug\/create\/create[\.-]/) {
+ # hack to allow the bug entry templates to use check_can_change_field
+ # to see if various field values should be available to the current user.
+ $vars->{'default'} = Bugzilla::Extension::BMO::FakeBug->new($vars->{'default'} || {});
+ }
+
+ if ($file =~ /^attachment\/diff-header\./) {
+ my $attachid = $vars->{attachid} ? $vars->{attachid} : $vars->{newid};
+ $vars->{attachment} = Bugzilla::Attachment->new({ id => $attachid, cache => 1 })
+ if $attachid;
+ }
+}
+
+sub page_before_template {
+ my ($self, $args) = @_;
+ my $page = $args->{'page_id'};
+ my $vars = $args->{'vars'};
+
+ if ($page eq 'user_activity.html') {
+ require Bugzilla::Extension::BMO::Reports::UserActivity;
+ Bugzilla::Extension::BMO::Reports::UserActivity::report($vars);
+
+ } elsif ($page eq 'triage_reports.html') {
+ require Bugzilla::Extension::BMO::Reports::Triage;
+ Bugzilla::Extension::BMO::Reports::Triage::report($vars);
+ }
+ elsif ($page eq 'group_admins.html') {
+ require Bugzilla::Extension::BMO::Reports::Groups;
+ Bugzilla::Extension::BMO::Reports::Groups::admins_report($vars);
+ }
+ elsif ($page eq 'group_membership.html' or $page eq 'group_membership.txt') {
+ require Bugzilla::Extension::BMO::Reports::Groups;
+ Bugzilla::Extension::BMO::Reports::Groups::membership_report($page, $vars);
+ }
+ elsif ($page eq 'group_members.html' or $page eq 'group_members.json') {
+ require Bugzilla::Extension::BMO::Reports::Groups;
+ Bugzilla::Extension::BMO::Reports::Groups::members_report($vars);
+ }
+ elsif ($page eq 'email_queue.html') {
+ require Bugzilla::Extension::BMO::Reports::EmailQueue;
+ Bugzilla::Extension::BMO::Reports::EmailQueue::report($vars);
+ }
+ elsif ($page eq 'release_tracking_report.html') {
+ require Bugzilla::Extension::BMO::Reports::ReleaseTracking;
+ Bugzilla::Extension::BMO::Reports::ReleaseTracking::report($vars);
+ }
+ elsif ($page eq 'product_security_report.html') {
+ require Bugzilla::Extension::BMO::Reports::ProductSecurity;
+ Bugzilla::Extension::BMO::Reports::ProductSecurity::report($vars);
+ }
+ elsif ($page eq 'fields.html') {
+ # Recently global/field-descs.none.tmpl and bug/field-help.none.tmpl
+ # were changed for better performance and are now only loaded once.
+ # I have not found an easy way to allow our hook template to check if
+ # it is called from pages/fields.html.tmpl. So we set a value in request_cache
+ # that our hook template can see.
+ Bugzilla->request_cache->{'bmo_fields_page'} = 1;
+ }
+ elsif ($page eq 'query_database.html') {
+ query_database($vars);
+ }
+}
+
+sub _get_field_values_sort_key {
+ my ($field) = @_;
+ my $dbh = Bugzilla->dbh;
+ my $fields = $dbh->selectall_arrayref(
+ "SELECT value, sortkey FROM $field
+ ORDER BY sortkey, value");
+
+ my %field_values;
+ foreach my $field (@$fields) {
+ my ($value, $sortkey) = @$field;
+ $field_values{$value} = $sortkey;
+ }
+ return \%field_values;
+}
+
+sub active_custom_fields {
+ my ($self, $args) = @_;
+ my $fields = $args->{'fields'};
+ my $params = $args->{'params'};
+ my $product = $params->{'product'};
+ my $component = $params->{'component'};
+
+ return if !$product;
+
+ my $product_name = blessed $product ? $product->name : $product;
+ my $component_name = blessed $component ? $component->name : $component;
+
+ my @tmp_fields;
+ foreach my $field (@$$fields) {
+ next if cf_hidden_in_product($field->name, $product_name, $component_name);
+ push(@tmp_fields, $field);
+ }
+ $$fields = \@tmp_fields;
+}
+
+sub cf_hidden_in_product {
+ my ($field_name, $product_name, $component_name) = @_;
+
+ # If used in buglist.cgi, we pass in one_product which is a Bugzilla::Product
+ # elsewhere, we just pass the name of the product.
+ $product_name = blessed($product_name)
+ ? $product_name->name
+ : $product_name;
+
+ # Also in buglist.cgi, we pass in a list of components instead
+ # of a single component name everywhere else.
+ my $component_list = [];
+ if ($component_name) {
+ $component_list = ref $component_name
+ ? $component_name
+ : [ $component_name ];
+ }
+
+ foreach my $field_re (keys %$cf_visible_in_products) {
+ if ($field_name =~ $field_re) {
+ # If no product given, for example more than one product
+ # in buglist.cgi, then hide field by default
+ return 1 if !$product_name;
+
+ my $products = $cf_visible_in_products->{$field_re};
+ foreach my $product (keys %$products) {
+ my $components = $products->{$product};
+
+ my $found_component = 0;
+ if (@$components) {
+ foreach my $component (@$components) {
+ if (ref($component) eq 'Regexp') {
+ if (grep($_ =~ $component, @$component_list)) {
+ $found_component = 1;
+ last;
+ }
+ } else {
+ if (grep($_ eq $component, @$component_list)) {
+ $found_component = 1;
+ last;
+ }
+ }
+ }
+ }
+
+ # If product matches and at at least one component matches
+ # from component_list (if a matching component was required),
+ # we allow the field to be seen
+ if ($product eq $product_name && (!@$components || $found_component)) {
+ return 0;
+ }
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+# Purpose: CC certain email addresses on bugmail when a bug is added or
+# removed from a particular group.
+sub bugmail_recipients {
+ my ($self, $args) = @_;
+ my $bug = $args->{'bug'};
+ my $recipients = $args->{'recipients'};
+ my $diffs = $args->{'diffs'};
+
+ if (@$diffs) {
+ # Changed bug
+ foreach my $ref (@$diffs) {
+ my $old = $ref->{old};
+ my $new = $ref->{new};
+ my $fieldname = $ref->{field_name};
+
+ if ($fieldname eq "bug_group") {
+ _cc_if_special_group($old, $recipients);
+ _cc_if_special_group($new, $recipients);
+ }
+ }
+ } else {
+ # Determine if it's a new bug, or a comment without a field change
+ my $comment_count = scalar @{$bug->comments};
+ if ($comment_count == 1) {
+ # New bug
+ foreach my $group (@{ $bug->groups_in }) {
+ _cc_if_special_group($group->{'name'}, $recipients);
+ }
+ }
+ }
+}
+
+sub _cc_if_special_group {
+ my ($group, $recipients) = @_;
+
+ return if !$group;
+
+ if (exists $group_change_notification{$group}) {
+ foreach my $login (@{ $group_change_notification{$group} }) {
+ my $id = login_to_id($login);
+ $recipients->{$id}->{+REL_CC} = Bugzilla::BugMail::BIT_DIRECT();
+ }
+ }
+}
+
+sub _check_trusted {
+ my ($field, $trusted, $priv_results) = @_;
+
+ my $needed_group = $trusted->{'_default'} || "";
+ foreach my $dfield (keys %$trusted) {
+ if ($field =~ $dfield) {
+ $needed_group = $trusted->{$dfield};
+ }
+ }
+ if ($needed_group && !Bugzilla->user->in_group($needed_group)) {
+ push (@$priv_results, PRIVILEGES_REQUIRED_EMPOWERED);
+ }
+}
+
+sub _is_field_set {
+ my $value = shift;
+ return $value ne '---' && $value !~ /\?$/;
+}
+
+sub bug_check_can_change_field {
+ my ($self, $args) = @_;
+ my $bug = $args->{'bug'};
+ my $field = $args->{'field'};
+ my $new_value = $args->{'new_value'};
+ my $old_value = $args->{'old_value'};
+ my $priv_results = $args->{'priv_results'};
+ my $user = Bugzilla->user;
+
+ if ($field =~ /^cf/ && !@$priv_results && $new_value ne '---') {
+ # "other" custom field setters restrictions
+ if (exists $cf_setters->{$field}) {
+ my $in_group = 0;
+ foreach my $group (@{$cf_setters->{$field}}) {
+ if ($user->in_group($group, $bug->product_id)) {
+ $in_group = 1;
+ last;
+ }
+ }
+ if (!$in_group) {
+ push (@$priv_results, PRIVILEGES_REQUIRED_EMPOWERED);
+ }
+ }
+ }
+ elsif ($field eq 'resolution' && $new_value eq 'EXPIRED') {
+ # The EXPIRED resolution should only be settable by gerv.
+ if ($user->login ne 'gerv@mozilla.org') {
+ push (@$priv_results, PRIVILEGES_REQUIRED_EMPOWERED);
+ }
+
+ } elsif ($field eq 'resolution' && $new_value eq 'FIXED') {
+ # You need at least canconfirm to mark a bug as FIXED
+ if (!$user->in_group('canconfirm', $bug->{'product_id'})) {
+ push (@$priv_results, PRIVILEGES_REQUIRED_EMPOWERED);
+ }
+
+ } elsif (
+ ($field eq 'bug_status' && $old_value eq 'VERIFIED')
+ || ($field eq 'dup_id' && $bug->status->name eq 'VERIFIED')
+ || ($field eq 'resolution' && $bug->status->name eq 'VERIFIED')
+ ) {
+ # You need at least editbugs to reopen a resolved/verified bug
+ if (!$user->in_group('editbugs', $bug->{'product_id'})) {
+ push (@$priv_results, PRIVILEGES_REQUIRED_EMPOWERED);
+ }
+
+ } elsif ($user->in_group('canconfirm', $bug->{'product_id'})) {
+ # Canconfirm is really "cantriage"; users with canconfirm can also mark
+ # bugs as DUPLICATE, WORKSFORME, and INCOMPLETE.
+ if ($field eq 'bug_status'
+ && is_open_state($old_value)
+ && !is_open_state($new_value))
+ {
+ push (@$priv_results, PRIVILEGES_REQUIRED_NONE);
+ }
+ elsif ($field eq 'resolution' &&
+ ($new_value eq 'DUPLICATE' ||
+ $new_value eq 'WORKSFORME' ||
+ $new_value eq 'INCOMPLETE'))
+ {
+ push (@$priv_results, PRIVILEGES_REQUIRED_NONE);
+ }
+
+ } elsif ($field eq 'bug_status') {
+ # Disallow reopening of bugs which have been resolved for > 1 year
+ if (is_open_state($new_value)
+ && !is_open_state($old_value)
+ && $bug->resolution eq 'FIXED')
+ {
+ my $days_ago = DateTime->now(time_zone => Bugzilla->local_timezone);
+ $days_ago->subtract(days => 365);
+ my $last_closed = datetime_from($bug->last_closed_date);
+ if ($last_closed lt $days_ago) {
+ push (@$priv_results, PRIVILEGES_REQUIRED_EMPOWERED);
+ }
+ }
+ }
+}
+
+# link up various Mozilla-specific strings
+sub bug_format_comment {
+ my ($self, $args) = @_;
+ my $regexes = $args->{'regexes'};
+
+ # link to crash-stats
+ # Only match if not already in an URL using the negative lookbehind (?<!\/)
+ push (@$regexes, {
+ match => qr/(?<!\/)\bbp-([a-f0-9]{8}\-[a-f0-9]{4}\-[a-f0-9]{4}\-
+ [a-f0-9]{4}\-[a-f0-9]{12})\b/x,
+ replace => sub {
+ my $args = shift;
+ my $match = html_quote($args->{matches}->[0]);
+ return qq{<a href="https://crash-stats.mozilla.com/report/index/$match">bp-$match</a>};
+ }
+ });
+
+ # link to CVE/CAN security releases
+ push (@$regexes, {
+ match => qr/(?<!\/|=)\b((?:CVE|CAN)-\d{4}-\d{4})\b/,
+ replace => sub {
+ my $args = shift;
+ my $match = html_quote($args->{matches}->[0]);
+ return qq{<a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=$match">$match</a>};
+ }
+ });
+
+ # link to svn.m.o
+ push (@$regexes, {
+ match => qr/\br(\d{4,})\b/,
+ replace => sub {
+ my $args = shift;
+ my $match = html_quote($args->{matches}->[0]);
+ return qq{<a href="http://viewvc.svn.mozilla.org/vc?view=rev&amp;revision=$match">r$match</a>};
+ }
+ });
+
+ # link bzr commit messages
+ push (@$regexes, {
+ match => qr/\b(Committing\s+to:\sbzr\+ssh:\/\/
+ (?:[^\@]+\@)?(bzr\.mozilla\.org[^\n]+)\n.*?\bCommitted\s)
+ (revision\s(\d+))/sx,
+ replace => sub {
+ my $args = shift;
+ my $preamble = html_quote($args->{matches}->[0]);
+ my $url = html_quote($args->{matches}->[1]);
+ my $text = html_quote($args->{matches}->[2]);
+ my $id = html_quote($args->{matches}->[3]);
+ $url =~ s/\s+$//;
+ $url =~ s/\/$//;
+ return qq{$preamble<a href="http://$url/revision/$id">$text</a>};
+ }
+ });
+
+ # link git.mozilla.org commit messages
+ push (@$regexes, {
+ match => qr#^(To\s(?:ssh://)?(?:[^\@]+\@)?git\.mozilla\.org[:/](.+?\.git)\n
+ \s+)([0-9a-z]+\.\.([0-9a-z]+)\s+\S+\s->\s\S+)#mx,
+ replace => sub {
+ my $args = shift;
+ my $preamble = html_quote($args->{matches}->[0]);
+ my $repo = html_quote($args->{matches}->[1]);
+ my $text = $args->{matches}->[2];
+ my $revision = $args->{matches}->[3];
+ return qq#$preamble<a href="http://git.mozilla.org/?p=$repo;a=commitdiff;h=$revision">$text</a>#;
+ }
+ });
+
+ # link to hg.m.o
+ # Note: for grouping in this regexp, always use non-capturing parentheses.
+ my $hgrepos = join('|', qw!(?:releases/)?comm-[\w.]+
+ (?:releases/)?mozilla-[\w.]+
+ (?:releases/)?mobile-[\w.]+
+ tracemonkey
+ tamarin-[\w.]+
+ camino!);
+
+ push (@$regexes, {
+ match => qr/\b(($hgrepos)\s+changeset:?\s+(?:\d+:)?([0-9a-fA-F]{12}))\b/,
+ replace => sub {
+ my $args = shift;
+ my $text = html_quote($args->{matches}->[0]);
+ my $repo = html_quote($args->{matches}->[1]);
+ my $id = html_quote($args->{matches}->[2]);
+ $repo = 'integration/mozilla-inbound' if $repo eq 'mozilla-inbound';
+ return qq{<a href="https://hg.mozilla.org/$repo/rev/$id">$text</a>};
+ }
+ });
+}
+
+sub quicksearch_map {
+ my ($self, $args) = @_;
+ my $map = $args->{'map'};
+
+ foreach my $name (keys %$map) {
+ if ($name =~ /cf_crash_signature$/) {
+ $map->{'sig'} = $name;
+ }
+ }
+}
+
+sub object_end_of_create {
+ my ($self, $args) = @_;
+ my $class = $args->{class};
+
+ if ($class eq 'Bugzilla::User') {
+ my $user = $args->{object};
+
+ # Log real IP addresses for auditing
+ _syslog(sprintf('[audit] <%s> created user %s', remote_ip(), $user->login));
+
+ # Add default searches to new user's footer
+ my $dbh = Bugzilla->dbh;
+
+ my $sharer = Bugzilla::User->new({ name => 'nobody@mozilla.org' })
+ or return;
+ my $group = Bugzilla::Group->new({ name => 'everyone' })
+ or return;
+
+ foreach my $definition (@default_named_queries) {
+ my ($namedquery_id) = _get_named_query($sharer->id, $group->id, $definition);
+ $dbh->do(
+ "INSERT INTO namedqueries_link_in_footer(namedquery_id,user_id) VALUES (?,?)",
+ undef,
+ $namedquery_id, $user->id
+ );
+ }
+
+ } elsif ($class eq 'Bugzilla::Bug') {
+ # Log real IP addresses for auditing
+ _syslog(sprintf('[audit] %s <%s> created bug %s',
+ Bugzilla->user->login, remote_ip(), $args->{object}->id));
+ }
+}
+
+sub _get_named_query {
+ my ($sharer_id, $group_id, $definition) = @_;
+ my $dbh = Bugzilla->dbh;
+ # find existing namedquery
+ my ($namedquery_id) = $dbh->selectrow_array(
+ "SELECT id FROM namedqueries WHERE userid=? AND name=?",
+ undef,
+ $sharer_id, $definition->{name}
+ );
+ return $namedquery_id if $namedquery_id;
+ # create namedquery
+ $dbh->do(
+ "INSERT INTO namedqueries(userid,name,query) VALUES (?,?,?)",
+ undef,
+ $sharer_id, $definition->{name}, $definition->{query}
+ );
+ $namedquery_id = $dbh->bz_last_key();
+ # and share it
+ $dbh->do(
+ "INSERT INTO namedquery_group_map(namedquery_id,group_id) VALUES (?,?)",
+ undef,
+ $namedquery_id, $group_id,
+ );
+ return $namedquery_id;
+}
+
+# Automatically CC users to bugs based on group & product
+sub bug_end_of_create {
+ my ($self, $args) = @_;
+ my $bug = $args->{'bug'};
+
+ foreach my $group_name (keys %group_auto_cc) {
+ my $group_obj = Bugzilla::Group->new({ name => $group_name });
+ if ($group_obj && $bug->in_group($group_obj)) {
+ my $ra_logins = exists $group_auto_cc{$group_name}->{$bug->product}
+ ? $group_auto_cc{$group_name}->{$bug->product}
+ : $group_auto_cc{$group_name}->{'_default'};
+ foreach my $login (@$ra_logins) {
+ $bug->add_cc($login);
+ }
+ }
+ }
+}
+
+# detect github pull requests and reviewboard reviews, set the content-type
+sub attachment_process_data {
+ my ($self, $args) = @_;
+ my $attributes = $args->{attributes};
+
+ # must be a text attachment
+ return unless $attributes->{mimetype} eq 'text/plain';
+
+ # check the attachment size, and get attachment content if it isn't too large
+ my $data = $attributes->{data};
+ my $url;
+ if (blessed($data) && blessed($data) eq 'Fh') {
+ # filehandle
+ my $size = -s $data;
+ return if $size > 256;
+ sysread($data, $url, $size);
+ seek($data, 0, 0);
+ } else {
+ # string
+ $url = $data;
+ }
+
+ if (my $content_type = _get_review_content_type($url)) {
+ $attributes->{mimetype} = $content_type;
+ $attributes->{ispatch} = 0;
+ }
+}
+
+sub _get_review_content_type {
+ my ($url) = @_;
+
+ # trim and check for the pull request url
+ return unless defined $url;
+ return if length($url) > 256;
+ $url = trim($url);
+ return if $url =~ /\s/;
+
+ if ($url =~ m#^https://github\.com/[^/]+/[^/]+/pull/\d+/?$#i) {
+ return GITHUB_PR_CONTENT_TYPE;
+ }
+ if ($url =~ m#^https?://reviewboard(?:-dev)?\.(?:allizom|mozilla)\.org/r/\d+/?#i) {
+ return RB_REQUEST_CONTENT_TYPE;
+ }
+ return;
+}
+
+# redirect automatically to github urls
+sub attachment_view {
+ my ($self, $args) = @_;
+ my $attachment = $args->{attachment};
+ my $cgi = Bugzilla->cgi;
+
+ # don't redirect if the content-type is specified explicitly
+ return if defined $cgi->param('content_type');
+
+ # must be our github/reviewboard content-type
+ return unless
+ $attachment->contenttype eq GITHUB_PR_CONTENT_TYPE
+ or $attachment->contenttype eq RB_REQUEST_CONTENT_TYPE;
+
+ # must still be a valid url
+ return unless _get_review_content_type($attachment->data);
+
+ # redirect
+ print $cgi->redirect(trim($attachment->data));
+ exit;
+}
+
+sub install_before_final_checks {
+ my ($self, $args) = @_;
+
+ # Add product chooser setting
+ add_setting('product_chooser',
+ ['pretty_product_chooser', 'full_product_chooser'],
+ 'pretty_product_chooser');
+
+ # Add option to inject x-bugzilla headers into the message body to work
+ # around gmail filtering limitations
+ add_setting('headers_in_body', ['on', 'off'], 'off');
+
+ # Migrate from 'gmail_threading' setting to 'bugmail_new_prefix'
+ my $dbh = Bugzilla->dbh;
+ if ($dbh->selectrow_array("SELECT 1 FROM setting WHERE name='gmail_threading'")) {
+ $dbh->bz_start_transaction();
+ $dbh->do("UPDATE profile_setting
+ SET setting_value='on-temp'
+ WHERE setting_name='gmail_threading' AND setting_value='Off'");
+ $dbh->do("UPDATE profile_setting
+ SET setting_value='off'
+ WHERE setting_name='gmail_threading' AND setting_value='On'");
+ $dbh->do("UPDATE profile_setting
+ SET setting_value='on'
+ WHERE setting_name='gmail_threading' AND setting_value='on-temp'");
+ $dbh->do("UPDATE profile_setting
+ SET setting_name='bugmail_new_prefix'
+ WHERE setting_name='gmail_threading'");
+ $dbh->do("DELETE FROM setting WHERE name='gmail_threading'");
+ $dbh->bz_commit_transaction();
+ }
+}
+
+# Migrate old is_active stuff to new patch (is in core in 4.2), The old column
+# name was 'is_active', the new one is 'isactive' (no underscore).
+sub install_update_db {
+ my $dbh = Bugzilla->dbh;
+
+ if ($dbh->bz_column_info('milestones', 'is_active')) {
+ $dbh->do("UPDATE milestones SET isactive = 0 WHERE is_active = 0;");
+ $dbh->bz_drop_column('milestones', 'is_active');
+ $dbh->bz_drop_column('milestones', 'is_searchable');
+ }
+}
+
+sub _last_closed_date {
+ my ($self) = @_;
+ my $dbh = Bugzilla->dbh;
+
+ return $self->{'last_closed_date'} if defined $self->{'last_closed_date'};
+
+ my $closed_statuses = "'" . join("','", map { $_->name } closed_bug_statuses()) . "'";
+ my $status_field_id = get_field_id('bug_status');
+
+ $self->{'last_closed_date'} = $dbh->selectrow_array("
+ SELECT bugs_activity.bug_when
+ FROM bugs_activity
+ WHERE bugs_activity.fieldid = ?
+ AND bugs_activity.added IN ($closed_statuses)
+ AND bugs_activity.bug_id = ?
+ ORDER BY bugs_activity.bug_when DESC " . $dbh->sql_limit(1),
+ undef, $status_field_id, $self->id
+ );
+
+ return $self->{'last_closed_date'};
+}
+
+sub field_end_of_create {
+ my ($self, $args) = @_;
+ my $field = $args->{'field'};
+
+ # Create an IT bug so Mozilla's DBAs so they can update the grants for metrics
+
+ if (Bugzilla->params->{'urlbase'} ne 'https://bugzilla.mozilla.org/'
+ && Bugzilla->params->{'urlbase'} ne 'https://bugzilla.allizom.org/')
+ {
+ return;
+ }
+
+ my $name = $field->name;
+
+ if (Bugzilla->usage_mode == USAGE_MODE_CMDLINE) {
+ Bugzilla->set_user(Bugzilla::User->check({ name => 'nobody@mozilla.org' }));
+ print "Creating IT permission grant bug for new field '$name'...";
+ }
+
+ my $bug_data = {
+ short_desc => "Custom field '$name' added to bugzilla.mozilla.org",
+ product => 'mozilla.org',
+ component => 'Server Operations: Database',
+ bug_severity => 'normal',
+ op_sys => 'All',
+ rep_platform => 'All',
+ version => 'other',
+ };
+
+ my $comment = <<COMMENT;
+The custom field '$name' has been added to the BMO database.
+Please run the following on bugzilla1.db.scl3.mozilla.com:
+COMMENT
+
+ if ($field->type == FIELD_TYPE_SINGLE_SELECT
+ || $field->type == FIELD_TYPE_MULTI_SELECT) {
+ $comment .= <<COMMENT;
+ GRANT SELECT ON `bugs`.`$name` TO 'metrics'\@'10.22.70.20_';
+ GRANT SELECT ON `bugs`.`$name` TO 'metrics'\@'10.22.70.21_';
+COMMENT
+ }
+ if ($field->type == FIELD_TYPE_MULTI_SELECT) {
+ $comment .= <<COMMENT;
+ GRANT SELECT ON `bugs`.`bug_$name` TO 'metrics'\@'10.22.70.20_';
+ GRANT SELECT ON `bugs`.`bug_$name` TO 'metrics'\@'10.22.70.21_';
+COMMENT
+ }
+ if ($field->type != FIELD_TYPE_MULTI_SELECT) {
+ $comment .= <<COMMENT;
+ GRANT SELECT ($name) ON `bugs`.`bugs` TO 'metrics'\@'10.22.70.20_';
+ GRANT SELECT ($name) ON `bugs`.`bugs` TO 'metrics'\@'10.22.70.21_';
+COMMENT
+ }
+
+ $bug_data->{'comment'} = $comment;
+
+ my $old_error_mode = Bugzilla->error_mode;
+ Bugzilla->error_mode(ERROR_MODE_DIE);
+
+ my $new_bug = eval { Bugzilla::Bug->create($bug_data) };
+
+ my $error = $@;
+ undef $@;
+ Bugzilla->error_mode($old_error_mode);
+
+ if ($error || !($new_bug && $new_bug->{'bug_id'})) {
+ warn "Error creating IT bug for new field $name: $error";
+ if (Bugzilla->usage_mode == USAGE_MODE_CMDLINE) {
+ print "\nError: $error\n";
+ }
+ }
+ else {
+ Bugzilla::BugMail::Send($new_bug->id, { changer => Bugzilla->user });
+ if (Bugzilla->usage_mode == USAGE_MODE_CMDLINE) {
+ print "bug " . $new_bug->id . " created.\n";
+ }
+ }
+}
+
+sub webservice {
+ my ($self, $args) = @_;
+
+ my $dispatch = $args->{dispatch};
+ $dispatch->{BMO} = "Bugzilla::Extension::BMO::WebService";
+}
+
+our $search_content_matches;
+BEGIN {
+ $search_content_matches = \&Bugzilla::Search::_content_matches;
+}
+
+sub search_operator_field_override {
+ my ($self, $args) = @_;
+ my $search = $args->{'search'};
+ my $operators = $args->{'operators'};
+
+ my $cgi = Bugzilla->cgi;
+ my @comments = $cgi->param('comments');
+ my $exclude_comments = scalar(@comments) && !grep { $_ eq '1' } @comments;
+
+ if ($cgi->param('query_format')
+ && $cgi->param('query_format') eq 'specific'
+ && $exclude_comments
+ ) {
+ # use the non-comment operator
+ $operators->{'content'}->{matches} = \&_short_desc_matches;
+ $operators->{'content'}->{notmatches} = \&_short_desc_matches;
+
+ } else {
+ # restore default content operator
+ $operators->{'content'}->{matches} = $search_content_matches;
+ $operators->{'content'}->{notmatches} = $search_content_matches;
+ }
+}
+
+sub _short_desc_matches {
+ # copy of Bugzilla::Search::_content_matches with comment searching removed
+
+ my ($self, $args) = @_;
+ my ($chart_id, $joins, $fields, $operator, $value) =
+ @$args{qw(chart_id joins fields operator value)};
+ my $dbh = Bugzilla->dbh;
+
+ # Add the fulltext table to the query so we can search on it.
+ my $table = "bugs_fulltext_$chart_id";
+ push(@$joins, { table => 'bugs_fulltext', as => $table });
+
+ # Create search terms to add to the SELECT and WHERE clauses.
+ my ($term, $rterm) =
+ $dbh->sql_fulltext_search("$table.short_desc", $value, 2);
+ $rterm = $term if !$rterm;
+
+ # The term to use in the WHERE clause.
+ if ($operator =~ /not/i) {
+ $term = "NOT($term)";
+ }
+ $args->{term} = $term;
+
+ my $current = $self->COLUMNS->{'relevance'}->{name};
+ $current = $current ? "$current + " : '';
+ # For NOT searches, we just add 0 to the relevance.
+ my $select_term = $operator =~ /not/ ? 0 : "($current$rterm)";
+ $self->COLUMNS->{'relevance'}->{name} = $select_term;
+}
+
+sub mailer_before_send {
+ my ($self, $args) = @_;
+ my $email = $args->{email};
+
+ _log_sent_email($email);
+
+ # $bug->mentors is added by the Review extension
+ if (Bugzilla::Bug->can('mentors')) {
+ _add_mentors_header($email);
+ }
+
+ # insert x-bugzilla headers into the body
+ _inject_headers_into_body($email);
+}
+
+# Log a summary of bugmail sent to the syslog, for auditing and monitoring
+sub _log_sent_email {
+ my $email = shift;
+
+ my $recipient = $email->header('to');
+ return unless $recipient;
+
+ my $subject = $email->header('Subject');
+
+ my $bug_id = $email->header('X-Bugzilla-ID');
+ if (!$bug_id && $subject =~ /[\[\(]Bug (\d+)/i) {
+ $bug_id = $1;
+ }
+ $bug_id = $bug_id ? "bug-$bug_id" : '-';
+
+ my $message_type;
+ my $type = $email->header('X-Bugzilla-Type');
+ my $reason = $email->header('X-Bugzilla-Reason');
+ if ($type eq 'whine' || $type eq 'request' || $type eq 'admin') {
+ $message_type = $type;
+ } elsif ($reason && $reason ne 'None') {
+ $message_type = $reason;
+ } else {
+ $message_type = $email->header('X-Bugzilla-Watch-Reason');
+ }
+ $message_type ||= $type || '?';
+
+ $subject =~ s/[\[\(]Bug \d+[\]\)]\s*//;
+
+ _syslog("[bugmail] $recipient ($message_type) $bug_id $subject");
+}
+
+# Add X-Bugzilla-Mentors field to bugmail
+sub _add_mentors_header {
+ my $email = shift;
+ return unless my $bug_id = $email->header('X-Bugzilla-ID');
+ return unless my $bug = Bugzilla::Bug->new({ id => $bug_id, cache => 1 });
+ return unless my $mentors = $bug->mentors;
+ return unless @$mentors;
+ $email->header_set('X-Bugzilla-Mentors', join(', ', map { $_->login } @$mentors));
+}
+
+sub _inject_headers_into_body {
+ my $email = shift;
+ my $replacement = '';
+
+ my $recipient = Bugzilla::User->new({ name => $email->header('To'), cache => 1 });
+ if ($recipient
+ && $recipient->settings->{headers_in_body}->{value} eq 'on')
+ {
+ my @headers;
+ my $it = natatime(2, $email->header_pairs);
+ while (my ($name, $value) = $it->()) {
+ next unless $name =~ /^X-Bugzilla-(.+)/;
+ if ($name eq 'X-Bugzilla-Flags' || $name eq 'X-Bugzilla-Changed-Field-Names') {
+ # these are multi-value fields, split on space
+ foreach my $v (split(/\s+/, $value)) {
+ push @headers, "$name: $v";
+ }
+ }
+ elsif ($name eq 'X-Bugzilla-Changed-Fields') {
+ # cannot split on space for this field, because field names contain
+ # spaces. instead work from a list of field names.
+ my @fields =
+ map { $_->description }
+ @{ Bugzilla->fields };
+ # these aren't real fields, but exist in the headers
+ push @fields, ('Comment Created', 'Attachment Created');
+ @fields =
+ sort { length($b) <=> length($a) }
+ @fields;
+ while ($value ne '') {
+ foreach my $field (@fields) {
+ if ($value eq $field) {
+ push @headers, "$name: $field";
+ $value = '';
+ last;
+ }
+ if (substr($value, 0, length($field) + 1) eq $field . ' ') {
+ push @headers, "$name: $field";
+ $value = substr($value, length($field) + 1);
+ last;
+ }
+ }
+ }
+ }
+ else {
+ push @headers, "$name: $value";
+ }
+ }
+ $replacement = join("\n", @headers);
+ }
+
+ # update the message body
+ if (scalar($email->parts) > 1) {
+ $email->walk_parts(sub {
+ my ($part) = @_;
+
+ # skip top-level
+ return if $part->parts > 1;
+
+ # do not filter attachments such as patches, etc.
+ return if
+ $part->header('Content-Disposition')
+ && $part->header('Content-Disposition') =~ /attachment/;
+
+ # text/plain|html only
+ return unless $part->content_type =~ /^text\/(?:html|plain)/;
+
+ # hide in html content
+ if ($replacement && $part->content_type =~ /^text\/html/) {
+ $replacement = '<pre style="font-size: 0pt; color: #fff">' . $replacement . '</pre>';
+ }
+
+ # and inject
+ _replace_placeholder_in_part($part, $replacement);
+ });
+
+ # force Email::MIME to re-create all the parts. without this
+ # as_string() doesn't return the updated body for multi-part sub-parts.
+ $email->parts_set([ $email->subparts ]);
+ }
+ else {
+ # text-only email
+ _replace_placeholder_in_part($email, $replacement);
+ }
+}
+
+sub _replace_placeholder_in_part {
+ my ($part, $replacement) = @_;
+
+ # fix encoding
+ my $body = $part->body;
+ if (Bugzilla->params->{'utf8'}) {
+ $part->charset_set('UTF-8');
+ my $raw = $part->body_raw;
+ if (utf8::is_utf8($raw)) {
+ utf8::encode($raw);
+ $part->body_set($raw);
+ }
+ }
+ $part->encoding_set('quoted-printable') if !is_7bit_clean($body);
+
+ # replace
+ my $placeholder = quotemeta('@@body-headers@@');
+ $body = $part->body_str;
+ $body =~ s/$placeholder/$replacement/;
+ $part->body_str_set($body);
+}
+
+sub _syslog {
+ my $message = shift;
+ openlog('apache', 'cons,pid', 'local4');
+ syslog('notice', encode_utf8($message));
+ closelog();
+}
+
+sub post_bug_after_creation {
+ my ($self, $args) = @_;
+ return unless my $format = Bugzilla->input_params->{format};
+ my $bug = $args->{vars}->{bug};
+
+ if ($format eq 'employee-incident'
+ && $bug->component eq 'Server Operations: Desktop Issues')
+ {
+ $self->_post_employee_incident_bug($args);
+ }
+ elsif ($format eq 'swag') {
+ $self->_post_gear_bug($args);
+ }
+ elsif ($format eq 'mozpr') {
+ $self->_post_mozpr_bug($args);
+ }
+}
+
+sub _post_employee_incident_bug {
+ my ($self, $args) = @_;
+ my $vars = $args->{vars};
+ my $bug = $vars->{bug};
+
+ my $error_mode_cache = Bugzilla->error_mode;
+ Bugzilla->error_mode(ERROR_MODE_DIE);
+
+ my $template = Bugzilla->template;
+ my $cgi = Bugzilla->cgi;
+
+ my ($investigate_bug, $ssh_key_bug);
+ my $old_user = Bugzilla->user;
+ eval {
+ Bugzilla->set_user(Bugzilla::User->new({ name => 'nobody@mozilla.org' }));
+ my $new_user = Bugzilla->user;
+
+ # HACK: User needs to be in the editbugs and primary bug's group to allow
+ # setting of dependencies.
+ $new_user->{'groups'} = [ Bugzilla::Group->new({ name => 'editbugs' }),
+ Bugzilla::Group->new({ name => 'infra' }),
+ Bugzilla::Group->new({ name => 'infrasec' }) ];
+
+ my $recipients = { changer => $new_user };
+ $vars->{original_reporter} = $old_user;
+
+ my $comment;
+ $cgi->param('display_action', '');
+ $template->process('bug/create/comment-employee-incident.txt.tmpl', $vars, \$comment)
+ || ThrowTemplateError($template->error());
+
+ $investigate_bug = Bugzilla::Bug->create({
+ short_desc => 'Investigate Lost Device',
+ product => 'mozilla.org',
+ component => 'Security Assurance: Incident',
+ status_whiteboard => '[infrasec:incident]',
+ bug_severity => 'critical',
+ cc => [ 'jstevensen@mozilla.com' ],
+ groups => [ 'infrasec' ],
+ comment => $comment,
+ op_sys => 'All',
+ rep_platform => 'All',
+ version => 'other',
+ dependson => $bug->bug_id,
+ });
+ $bug->set_all({ blocked => { add => [ $investigate_bug->bug_id ] }});
+ Bugzilla::BugMail::Send($investigate_bug->id, $recipients);
+
+ Bugzilla->set_user($old_user);
+ $vars->{original_reporter} = '';
+ $comment = '';
+ $cgi->param('display_action', 'ssh');
+ $template->process('bug/create/comment-employee-incident.txt.tmpl', $vars, \$comment)
+ || ThrowTemplateError($template->error());
+
+ $ssh_key_bug = Bugzilla::Bug->create({
+ short_desc => 'Disable/Regenerate SSH Key',
+ product => $bug->product,
+ component => $bug->component,
+ bug_severity => 'critical',
+ cc => $bug->cc,
+ groups => [ map { $_->{name} } @{ $bug->groups } ],
+ comment => $comment,
+ op_sys => 'All',
+ rep_platform => 'All',
+ version => 'other',
+ dependson => $bug->bug_id,
+ });
+ $bug->set_all({ blocked => { add => [ $ssh_key_bug->bug_id ] }});
+ Bugzilla::BugMail::Send($ssh_key_bug->id, $recipients);
+ };
+ my $error = $@;
+
+ Bugzilla->set_user($old_user);
+ Bugzilla->error_mode($error_mode_cache);
+
+ if ($error || !$investigate_bug || !$ssh_key_bug) {
+ warn "Failed to create additional employee-incident bug: $error" if $error;
+ $vars->{'message'} = 'employee_incident_creation_failed';
+ }
+}
+
+sub _post_gear_bug {
+ my ($self, $args) = @_;
+ my $vars = $args->{vars};
+ my $bug = $vars->{bug};
+ my $input = Bugzilla->input_params;
+
+ my ($team, $code) = $input->{teamcode} =~ /^(.+?) \((\d+)\)$/;
+ my @request = (
+ "Date Required: $input->{date_required}",
+ "$input->{firstname} $input->{lastname}",
+ $input->{email},
+ $input->{mozspace},
+ $team,
+ $code,
+ $input->{purpose},
+ );
+ my @recipient = (
+ "$input->{shiptofirstname} $input->{shiptolastname}",
+ $input->{shiptoemail},
+ $input->{shiptoaddress1},
+ $input->{shiptoaddress2},
+ $input->{shiptocity},
+ $input->{shiptostate},
+ $input->{shiptopostcode},
+ $input->{shiptocountry},
+ "Phone: $input->{shiptophone}",
+ $input->{shiptoidrut},
+ );
+
+ # the csv has 14 item fields
+ my @items = map { trim($_) } split(/\n/, $input->{items});
+ my @csv;
+ while (@items) {
+ my @batch;
+ if (scalar(@items) > 14) {
+ @batch = splice(@items, 0, 14);
+ }
+ else {
+ @batch = @items;
+ push @batch, '' for scalar(@items)..13;
+ @items = ();
+ }
+ push @csv, [ @request, @batch, @recipient ];
+ }
+
+ # csv quoting and concat
+ foreach my $line (@csv) {
+ foreach my $field (@$line) {
+ if ($field =~ s/"/""/g || $field =~ /,/) {
+ $field = qq#"$field"#;
+ }
+ }
+ $line = join(',', @$line);
+ }
+
+ $self->_add_attachment($args, {
+ data => join("\n", @csv),
+ description => "Items (CSV)",
+ filename => "gear_" . $bug->id . ".csv",
+ mimetype => "text/csv",
+ });
+ $bug->update($bug->creation_ts);
+}
+
+sub _post_mozpr_bug {
+ my ($self, $args) = @_;
+ my $vars = $args->{vars};
+ my $bug = $vars->{bug};
+ my $input = Bugzilla->input_params;
+
+ if ($input->{proj_mat_file}) {
+ $self->_add_attachment($args, {
+ data => $input->{proj_mat_file_attach},
+ description => $input->{proj_mat_file_desc},
+ filename => scalar $input->{proj_mat_file_attach},
+ });
+ }
+ if ($input->{pr_mat_file}) {
+ $self->_add_attachment($args, {
+ data => $input->{pr_mat_file_attach},
+ description => $input->{pr_mat_file_desc},
+ filename => scalar $input->{pr_mat_file_attach},
+ });
+ }
+ $bug->update($bug->creation_ts);
+}
+
+sub _add_attachment {
+ my ($self, $args, $attachment_args) = @_;
+
+ my $bug = $args->{vars}->{bug};
+ $attachment_args->{bug} = $bug;
+ $attachment_args->{creation_ts} = $bug->creation_ts;
+ $attachment_args->{ispatch} = 0 unless exists $attachment_args->{ispatch};
+ $attachment_args->{isprivate} = 0 unless exists $attachment_args->{isprivate};
+ $attachment_args->{mimetype} ||= $self->_detect_content_type($attachment_args->{data});
+
+ # If the attachment cannot be successfully added to the bug,
+ # we notify the user, but we don't interrupt the bug creation process.
+ my $old_error_mode = Bugzilla->error_mode;
+ Bugzilla->error_mode(ERROR_MODE_DIE);
+ my $attachment;
+ eval {
+ $attachment = Bugzilla::Attachment->create($attachment_args);
+ };
+ warn "$@" if $@;
+ Bugzilla->error_mode($old_error_mode);
+
+ if ($attachment) {
+ # Insert comment for attachment
+ $bug->add_comment('', { isprivate => 0,
+ type => CMT_ATTACHMENT_CREATED,
+ extra_data => $attachment->id });
+ delete $bug->{attachments};
+ }
+ else {
+ $args->{vars}->{'message'} = 'attachment_creation_failed';
+ }
+
+ # Note: you must call $bug->update($bug->creation_ts) after adding all attachments
+}
+
+# bugzilla's content_type detection makes assumptions about form fields, which
+# means we can't use it here. this code is lifted from
+# Bugzilla::Attachment::get_content_type and the TypeSniffer extension.
+sub _detect_content_type {
+ my ($self, $data) = @_;
+ my $cgi = Bugzilla->cgi;
+
+ # browser provided content-type
+ my $content_type = $cgi->uploadInfo($data)->{'Content-Type'};
+ $content_type = 'image/png' if $content_type eq 'image/x-png';
+
+ if ($content_type eq 'application/octet-stream') {
+ # detect from filename
+ my $filename = scalar($data);
+ if (my $from_filename = mimetype($filename)) {
+ return $from_filename;
+ }
+ }
+
+ return $content_type || 'application/octet-stream';
+}
+
+sub buglist_columns {
+ my ($self, $args) = @_;
+ my $columns = $args->{columns};
+ $columns->{'cc_count'} = {
+ name => '(SELECT COUNT(*) FROM cc WHERE cc.bug_id = bugs.bug_id)',
+ title => 'CC Count',
+ };
+ $columns->{'dupe_count'} = {
+ name => '(SELECT COUNT(*) FROM duplicates WHERE duplicates.dupe_of = bugs.bug_id)',
+ title => 'Duplicate Count',
+ };
+}
+
+sub enter_bug_start {
+ my ($self, $args) = @_;
+ # if configured with create_bug_formats, force users into a custom bug
+ # format (can be overridden with a __standard__ format)
+ my $cgi = Bugzilla->cgi;
+ if ($cgi->param('format') && $cgi->param('format') eq '__standard__') {
+ $cgi->delete('format');
+ } elsif (my $format = forced_format($cgi->param('product'))) {
+ $cgi->param('format', $format);
+ }
+
+ # If product eq 'mozilla.org' and format eq 'itrequest', then
+ # switch to the new 'Infrastructure & Operations' product.
+ if ($cgi->param('product') && $cgi->param('product') eq 'mozilla.org'
+ && $cgi->param('format') && $cgi->param('format') eq 'itrequest')
+ {
+ $cgi->param('product', 'Infrastructure & Operations');
+ }
+
+ # map renamed groups
+ $cgi->param('groups', _map_groups($cgi->param('groups')));
+}
+
+sub bug_before_create {
+ my ($self, $args) = @_;
+ my $params = $args->{params};
+ if (exists $params->{groups}) {
+ # map renamed groups
+ $params->{groups} = [ _map_groups($params->{groups}) ];
+ }
+}
+
+sub _map_groups {
+ my (@groups) = @_;
+ return unless @groups;
+ @groups = @{ $groups[0] } if ref($groups[0]);
+ return map {
+ # map mozilla-corporation-confidential => mozilla-employee-confidential
+ $_ eq 'mozilla-corporation-confidential'
+ ? 'mozilla-employee-confidential'
+ : $_
+ } @groups;
+}
+
+sub forced_format {
+ # note: this is also called from the guided bug entry extension
+ my ($product) = @_;
+ return undef unless defined $product;
+
+ # always work on the correct product name
+ $product = Bugzilla::Product->new({ name => $product, cache => 1 })
+ unless blessed($product);
+ return undef unless $product;
+
+ # check for a forced-format entry
+ my $forced = $create_bug_formats{$product->name}
+ || return;
+
+ # should this user be included?
+ my $user = Bugzilla->user;
+ my $include = ref($forced->{include}) ? $forced->{include} : [ $forced->{include} ];
+ foreach my $inc (@$include) {
+ return $forced->{format} if $user->in_group($inc);
+ }
+
+ return undef;
+}
+
+sub query_database {
+ my ($vars) = @_;
+
+ # validate group membership
+ my $user = Bugzilla->user;
+ $user->in_group('query_database')
+ || ThrowUserError('auth_failure', { group => 'query_database',
+ action => 'access',
+ object => 'query_database' });
+
+ # read query
+ my $input = Bugzilla->input_params;
+ my $query = $input->{query};
+ $vars->{query} = $query;
+
+ if ($query) {
+ trick_taint($query);
+ $vars->{executed} = 1;
+
+ # add limit if missing
+ if ($query !~ /\sLIMIT\s+\d+\s*$/si) {
+ $query .= ' LIMIT 1000';
+ $vars->{query} = $query;
+ }
+
+ # log query
+ _syslog(sprintf("[db_query] %s %s", $user->login, $query));
+
+ # connect to database and execute
+ # switching to the shadow db gives us a read-only connection
+ my $dbh = Bugzilla->switch_to_shadow_db();
+ my $sth;
+ eval {
+ $sth = $dbh->prepare($query);
+ $sth->execute();
+ };
+ if ($@) {
+ $vars->{sql_error} = $@;
+ return;
+ }
+
+ # build result
+ my $columns = $sth->{NAME};
+ my $rows;
+ while (my @row = $sth->fetchrow_array) {
+ push @$rows, \@row;
+ }
+
+ # return results
+ $vars->{columns} = $columns;
+ $vars->{rows} = $rows;
+ }
+}
+
+# you can always file bugs into a product's default security group, as well as
+# into any of the groups in @always_fileable_groups
+sub _group_always_settable {
+ my ($self, $group) = @_;
+ return
+ $group->name eq $self->default_security_group
+ || ((grep { $_ eq $group->name } @always_fileable_groups) ? 1 : 0);
+}
+
+sub _default_security_group {
+ my ($self) = @_;
+ return exists $product_sec_groups{$self->name}
+ ? $product_sec_groups{$self->name}
+ : $product_sec_groups{_default};
+}
+
+sub _default_security_group_obj {
+ my ($self) = @_;
+ return unless my $group_name = $self->default_security_group;
+ return Bugzilla::Group->new({ name => $group_name, cache => 1 })
+}
+
+# called from the verify version, component, and group page.
+# if we're making a group invalid, stuff the default group into the cgi param
+# to make it checked by default.
+sub _check_default_product_security_group {
+ my ($self, $product, $invalid_groups, $optional_group_controls) = @_;
+ return unless my $group = $product->default_security_group_obj;
+ if (@$invalid_groups) {
+ my $cgi = Bugzilla->cgi;
+ my @groups = $cgi->param('groups');
+ push @groups, $group->name unless grep { $_ eq $group->name } @groups;
+ $cgi->param('groups', @groups);
+ }
+}
+
+sub install_filesystem {
+ my ($self, $args) = @_;
+ my $files = $args->{files};
+ my $extensions_dir = bz_locations()->{extensionsdir};
+ $files->{"$extensions_dir/BMO/bin/migrate-github-pull-requests.pl"} = {
+ perms => Bugzilla::Install::Filesystem::OWNER_EXECUTE
+ };
+}
+
+# "deleted" comment tag
+
+sub config_modify_panels {
+ my ($self, $args) = @_;
+ push @{ $args->{panels}->{groupsecurity}->{params} }, {
+ name => 'delete_comments_group',
+ type => 's',
+ choices => \&Bugzilla::Config::GroupSecurity::_get_all_group_names,
+ default => 'admin',
+ checker => \&check_group
+ };
+}
+
+sub comment_after_add_tag {
+ my ($self, $args) = @_;
+ my $tag = $args->{tag};
+ return unless lc($tag) eq 'deleted';
+
+ my $group_name = Bugzilla->params->{delete_comments_group};
+ if (!$group_name || !Bugzilla->user->in_group($group_name)) {
+ ThrowUserError('auth_failure', { group => $group_name,
+ action => 'delete',
+ object => 'comments' });
+ }
+}
+
+sub comment_after_remove_tag {
+ my ($self, $args) = @_;
+ my $tag = $args->{tag};
+ return unless lc($tag) eq 'deleted';
+
+ my $group_name = Bugzilla->params->{delete_comments_group};
+ if (!$group_name || !Bugzilla->user->in_group($group_name)) {
+ ThrowUserError('auth_failure', { group => $group_name,
+ action => 'delete',
+ object => 'comments' });
+ }
+}
+
+BEGIN {
+ *Bugzilla::Comment::has_tag = \&_comment_has_tag;
+}
+
+sub _comment_has_tag {
+ my ($self, $test_tag) = @_;
+ $test_tag = lc($test_tag);
+ foreach my $tag (@{ $self->tags }) {
+ return 1 if lc($tag) eq $test_tag;
+ }
+ return 0;
+}
+
+sub bug_comments {
+ my ($self, $args) = @_;
+ my $can_delete = Bugzilla->user->in_group(Bugzilla->params->{delete_comments_group});
+ my $comments = $args->{comments};
+ my @deleted = grep { $_->has_tag('deleted') } @$comments;
+ while (my $comment = pop @deleted) {
+ for (my $i = scalar(@$comments) - 1; $i >= 0; $i--) {
+ if ($comment == $comments->[$i]) {
+ if ($can_delete) {
+ # don't remove comment from users who can "delete" them
+ # just collapse it instead
+ $comment->{collapsed} = 1;
+ }
+ else {
+ # otherwise, remove it from the array
+ splice(@$comments, $i, 1);
+ }
+ last;
+ }
+ }
+ }
+}
+
+__PACKAGE__->NAME;
diff --git a/extensions/BMO/bin/bug_1022707.pl b/extensions/BMO/bin/bug_1022707.pl
new file mode 100755
index 000000000..c27757220
--- /dev/null
+++ b/extensions/BMO/bin/bug_1022707.pl
@@ -0,0 +1,50 @@
+#!/usr/bin/perl
+
+# 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.
+
+use strict;
+use warnings;
+
+use FindBin qw($RealBin);
+use lib "$RealBin/../../..";
+
+use Bugzilla;
+use Bugzilla::Constants qw( USAGE_MODE_CMDLINE );
+BEGIN { Bugzilla->extensions() }
+
+Bugzilla->usage_mode(USAGE_MODE_CMDLINE);
+
+my $dbh = Bugzilla->dbh;
+
+my $sql = q{
+ SELECT flags.id FROM flags
+ INNER JOIN bugs ON bugs.bug_id = flags.bug_id
+ WHERE type_id = 748
+ AND bugs.product_id != 21
+};
+
+print "Searching for suitable flags..\n";
+my $flag_ids = $dbh->selectcol_arrayref($sql);
+my $total = @$flag_ids;
+
+die "No suitable flags found\n" unless $total;
+print "About to fix $total flags\n";
+print "Press <enter> to start, or ^C to cancel...\n";
+readline;
+
+my $update_fsa_sql= "UPDATE flag_state_activity SET type_id = 4 WHERE " . $dbh->sql_in('flag_id', $flag_ids);
+my $update_flags_sql = "UPDATE flags SET type_id = 4 WHERE " . $dbh->sql_in('id', $flag_ids);
+
+$dbh->bz_start_transaction();
+$dbh->do($update_fsa_sql);
+$dbh->do($update_flags_sql);
+$dbh->bz_commit_transaction();
+
+Bugzilla->memcached->clear_all();
+
+print "Done.\n";
diff --git a/extensions/BMO/bin/migrate-github-pull-requests.pl b/extensions/BMO/bin/migrate-github-pull-requests.pl
new file mode 100755
index 000000000..de71a7856
--- /dev/null
+++ b/extensions/BMO/bin/migrate-github-pull-requests.pl
@@ -0,0 +1,90 @@
+#!/usr/bin/perl
+
+# 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.
+
+use strict;
+use warnings;
+
+use FindBin qw($RealBin);
+use lib "$RealBin/../../..";
+
+use Bugzilla;
+BEGIN { Bugzilla->extensions() }
+
+use Bugzilla::Extension::BMO::Data;
+use Bugzilla::Field;
+use Bugzilla::Install::Util qw(indicate_progress);
+use Bugzilla::User;
+use Bugzilla::Util qw(trim);
+
+my $dbh = Bugzilla->dbh;
+my $nobody = Bugzilla::User->check({ name => 'nobody@mozilla.org' });
+my $field = Bugzilla::Field->check({ name => 'attachments.mimetype' });
+
+# grab list of suitable attachments
+
+my $sql = <<EOF;
+SELECT attachments.attach_id,
+ attachments.bug_id,
+ attachments.mimetype,
+ attach_data.thedata
+ FROM attachments
+ INNER JOIN attach_data ON attach_data.id = attachments.attach_id
+ WHERE ispatch = 0
+ AND mimetype = 'text/plain'
+ AND thedata IS NOT NULL
+ AND LENGTH(thedata) > 0
+ AND LENGTH(thedata) <= 256
+EOF
+print "Searching for suitable attachments..\n";
+my $attachments = $dbh->selectall_arrayref($sql, { Slice => {} });
+my ($current, $total, $updated) = (1, scalar(@$attachments), 0);
+
+die "No suitable attachments found\n" unless $total;
+print "About to check $total attachments for github pull requests, and\n";
+print "update content-type if required.\n";
+print "Press <enter> to start, or ^C to cancel...\n";
+<>;
+
+foreach my $attachment (@$attachments) {
+ indicate_progress({ current => $current++, total => $total, every => 25 });
+
+ # check payload
+ my $url = trim($attachment->{thedata});
+ next if $url =~ /\s/;
+ next unless $url =~ m#^https://github\.com/[^/]+/[^/]+/pull/\d+\/?$#i;
+
+ $dbh->bz_start_transaction;
+
+ # set content-type
+ $dbh->do(
+ "UPDATE attachments SET mimetype = ? WHERE attach_id = ?",
+ undef,
+ GITHUB_PR_CONTENT_TYPE, $attachment->{attach_id}
+ );
+
+ # insert into bugs_activity
+ my $timestamp = $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
+ $dbh->do(
+ "INSERT INTO bugs_activity(bug_id, who, bug_when, fieldid, removed, added)
+ VALUES (?, ?, ?, ?, ?, ?)",
+ undef,
+ $attachment->{bug_id}, $nobody->id, $timestamp, $field->id,
+ $attachment->{mimetype}, GITHUB_PR_CONTENT_TYPE
+ );
+ $dbh->do(
+ "UPDATE bugs SET delta_ts = ?, lastdiffed = ? WHERE bug_id = ?",
+ undef,
+ $timestamp, $timestamp, $attachment->{bug_id}
+ );
+
+ $dbh->bz_commit_transaction;
+ $updated++;
+}
+
+print "Attachments updated: $updated\n";
diff --git a/extensions/BMO/lib/Constants.pm b/extensions/BMO/lib/Constants.pm
new file mode 100644
index 000000000..23eaae9cb
--- /dev/null
+++ b/extensions/BMO/lib/Constants.pm
@@ -0,0 +1,33 @@
+# -*- 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 BMO Bugzilla Extension.
+#
+# The Initial Developer of the Original Code is the Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2007
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# David Lawrence <dkl@mozilla.com>
+
+package Bugzilla::Extension::BMO::Constants;
+use strict;
+use base qw(Exporter);
+our @EXPORT = qw(
+ REQUEST_MAX_ATTACH_LINES
+);
+
+# Maximum attachment size in lines that will be sent with a
+# requested attachment flag notification.
+use constant REQUEST_MAX_ATTACH_LINES => 1000;
+
+1;
diff --git a/extensions/BMO/lib/Data.pm b/extensions/BMO/lib/Data.pm
new file mode 100644
index 000000000..7d0ec05fd
--- /dev/null
+++ b/extensions/BMO/lib/Data.pm
@@ -0,0 +1,242 @@
+# 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.
+
+package Bugzilla::Extension::BMO::Data;
+use strict;
+
+use base qw(Exporter);
+use Tie::IxHash;
+
+our @EXPORT = qw( $cf_visible_in_products
+ %group_change_notification
+ $cf_setters
+ @always_fileable_groups
+ %group_auto_cc
+ %product_sec_groups
+ %create_bug_formats
+ @default_named_queries
+ GITHUB_PR_CONTENT_TYPE
+ RB_REQUEST_CONTENT_TYPE );
+
+use constant GITHUB_PR_CONTENT_TYPE => 'text/x-github-pull-request';
+use constant RB_REQUEST_CONTENT_TYPE => 'text/x-review-board-request';
+
+# Which custom fields are visible in which products and components.
+#
+# By default, custom fields are visible in all products. However, if the name
+# of the field matches any of these regexps, it is only visible if the
+# product (and component if necessary) is a member of the attached hash. []
+# for component means "all".
+#
+# IxHash keeps them in insertion order, and so we get regexp priorities right.
+our $cf_visible_in_products;
+tie(%$cf_visible_in_products, "Tie::IxHash",
+ qr/^cf_colo_site$/ => {
+ "mozilla.org" => [
+ "Server Operations",
+ "Server Operations: DCOps",
+ "Server Operations: Projects",
+ "Server Operations: RelEng",
+ "Server Operations: Security",
+ ],
+ "Infrastructure & Operations" => [
+ "RelOps",
+ "RelOps: Puppet"
+ ],
+ },
+ qw/^cf_office$/ => {
+ "mozilla.org" => ["Server Operations: Desktop Issues"],
+ },
+ qr/^cf_crash_signature$/ => {
+ "Add-on SDK" => [],
+ "addons.mozilla.org" => [],
+ "Android Background Services" => [],
+ "Calendar" => [],
+ "Camino" => [],
+ "Composer" => [],
+ "Core" => [],
+ "Directory" => [],
+ "Fennec" => [],
+ "Firefox" => [],
+ "Firefox for Android" => [],
+ "Firefox for Metro" => [],
+ "Firefox OS" => [],
+ "JSS" => [],
+ "MailNews Core" => [],
+ "Mozilla Labs" => [],
+ "Mozilla Localizations" => [],
+ "mozilla.org" => [],
+ "Mozilla Services" => [],
+ "NSPR" => [],
+ "NSS" => [],
+ "Other Applications" => [],
+ "Penelope" => [],
+ "Plugins" => [],
+ "Release Engineering" => [],
+ "Rhino" => [],
+ "SeaMonkey" => [],
+ "Tamarin" => [],
+ "Tech Evangelism" => [],
+ "Testing" => [],
+ "Thunderbird" => [],
+ "Toolkit" => [],
+ },
+ qw/^cf_due_date$/ => {
+ "bugzilla.mozilla.org" => [],
+ "Community Building" => [],
+ "Data & BI Services Team" => [],
+ "Developer Engagement" => [],
+ "Infrastructure & Operations" => [],
+ "Marketing" => [],
+ "mozilla.org" => ["Security Assurance: Review Request"],
+ "Mozilla Reps" => [],
+ },
+ qw/^cf_locale$/ => {
+ "Mozilla Localizations" => ['Other'],
+ "www.mozilla.org" => [],
+ },
+ qw/^cf_mozilla_project$/ => {
+ "Data & BI Services Team" => [],
+ },
+ qw/^cf_machine_state$/ => {
+ "Release Engineering" => ["Buildduty"],
+ },
+);
+
+# Who to CC on particular bugmails when certain groups are added or removed.
+our %group_change_notification = (
+ 'addons-security' => ['amo-editors@mozilla.org'],
+ 'bugzilla-security' => ['security@bugzilla.org'],
+ 'client-services-security' => ['amo-admins@mozilla.org', 'web-security@mozilla.org'],
+ 'core-security' => ['security@mozilla.org'],
+ 'mozilla-services-security' => ['web-security@mozilla.org'],
+ 'tamarin-security' => ['tamarinsecurity@adobe.com'],
+ 'websites-security' => ['web-security@mozilla.org'],
+ 'webtools-security' => ['web-security@mozilla.org'],
+);
+
+# Who can set custom flags (use full field names only, not regex's)
+our $cf_setters = {
+ 'cf_colo_site' => ['infra', 'build'],
+};
+
+# Groups in which you can always file a bug, regardless of product or user.
+our @always_fileable_groups = qw(
+ addons-security
+ bugzilla-security
+ client-services-security
+ consulting
+ core-security
+ finance
+ infra
+ infrasec
+ l20n-security
+ marketing-private
+ mozilla-confidential
+ mozilla-employee-confidential
+ mozilla-foundation-confidential
+ mozilla-engagement
+ mozilla-messaging-confidential
+ partner-confidential
+ payments-confidential
+ tamarin-security
+ websites-security
+ webtools-security
+ winqual-data
+);
+
+# Mapping of products to their security bits
+our %product_sec_groups = (
+ "addons.mozilla.org" => 'client-services-security',
+ "Air Mozilla" => 'mozilla-employee-confidential',
+ "Android Background Services" => 'mozilla-services-security',
+ "Audio/Visual Infrastructure" => 'mozilla-employee-confidential',
+ "AUS" => 'client-services-security',
+ "Bugzilla" => 'bugzilla-security',
+ "bugzilla.mozilla.org" => 'bugzilla-security',
+ "Community Tools" => 'websites-security',
+ "Data & BI Services Team" => 'metrics-private',
+ "Developer Documentation" => 'websites-security',
+ "Developer Ecosystem" => 'client-services-security',
+ "Finance" => 'finance',
+ "Firefox Health Report" => 'mozilla-services-security',
+ "Infrastructure & Operations" => 'mozilla-employee-confidential',
+ "Input" => 'websites-security',
+ "Intellego" => 'intellego-team',
+ "Internet Public Policy" => 'mozilla-employee-confidential',
+ "L20n" => 'l20n-security',
+ "Legal" => 'legal',
+ "Marketing" => 'marketing-private',
+ "Marketplace" => 'client-services-security',
+ "Mozilla Communities" => 'mozilla-communities-security',
+ "Mozilla Corporation" => 'mozilla-employee-confidential',
+ "Mozilla Developer Network" => 'websites-security',
+ "Mozilla Foundation" => 'mozilla-employee-confidential',
+ "Mozilla Grants" => 'grants',
+ "mozillaignite" => 'websites-security',
+ "Mozilla Messaging" => 'mozilla-messaging-confidential',
+ "Mozilla Metrics" => 'metrics-private',
+ "mozilla.org" => 'mozilla-employee-confidential',
+ "Mozilla PR" => 'pr-private',
+ "Mozilla QA" => 'mozilla-employee-confidential',
+ "Mozilla Reps" => 'mozilla-reps',
+ "Mozilla Services" => 'mozilla-services-security',
+ "Popcorn" => 'websites-security',
+ "Privacy" => 'privacy',
+ "quality.mozilla.org" => 'websites-security',
+ "Release Engineering" => 'mozilla-employee-confidential',
+ "Snippets" => 'websites-security',
+ "Socorro" => 'client-services-security',
+ "support.mozillamessaging.com" => 'websites-security',
+ "support.mozilla.org" => 'websites-security',
+ "Talkback" => 'talkback-private',
+ "Tamarin" => 'tamarin-security',
+ "Testopia" => 'bugzilla-security',
+ "Tree Management" => 'mozilla-employee-confidential',
+ "Web Apps" => 'client-services-security',
+ "Webmaker" => 'websites-security',
+ "Websites" => 'websites-security',
+ "Webtools" => 'webtools-security',
+ "www.mozilla.org" => 'websites-security',
+ "Mozilla Foundation Operations" => 'mozilla-foundation-operations',
+ "_default" => 'core-security'
+);
+
+# Automatically CC users to bugs filed into configured groups and products
+our %group_auto_cc = (
+ 'partner-confidential' => {
+ 'Marketing' => ['jbalaco@mozilla.com'],
+ '_default' => ['mbest@mozilla.com'],
+ },
+);
+
+# Force create-bug template by product
+# Users in 'include' group will be forced into using the form.
+our %create_bug_formats = (
+ 'Mozilla Developer Network' => {
+ 'format' => 'mdn',
+ 'include' => 'everyone',
+ },
+ 'Legal' => {
+ 'format' => 'legal',
+ 'include' => 'everyone',
+ },
+ 'Internet Public Policy' => {
+ 'format' => 'ipp',
+ 'include' => 'everyone',
+ },
+);
+
+# List of named queries which will be added to new users' footer
+our @default_named_queries = (
+ {
+ name => 'Bugs Filed Today',
+ query => 'query_format=advanced&chfieldto=Now&chfield=[Bug creation]&chfieldfrom=-24h&order=bug_id',
+ },
+);
+
+1;
diff --git a/extensions/BMO/lib/FakeBug.pm b/extensions/BMO/lib/FakeBug.pm
new file mode 100644
index 000000000..6127cb560
--- /dev/null
+++ b/extensions/BMO/lib/FakeBug.pm
@@ -0,0 +1,42 @@
+package Bugzilla::Extension::BMO::FakeBug;
+
+# hack to allow the bug entry templates to use check_can_change_field to see if
+# various field values should be available to the current user
+
+use strict;
+
+use Bugzilla::Bug;
+
+our $AUTOLOAD;
+
+sub new {
+ my $class = shift;
+ my $self = shift;
+ bless $self, $class;
+ return $self;
+}
+
+sub AUTOLOAD {
+ my $self = shift;
+ my $name = $AUTOLOAD;
+ $name =~ s/.*://;
+ return exists $self->{$name} ? $self->{$name} : undef;
+}
+
+sub check_can_change_field {
+ my $self = shift;
+ return Bugzilla::Bug::check_can_change_field($self, @_)
+}
+
+sub _changes_everconfirmed {
+ my $self = shift;
+ return Bugzilla::Bug::_changes_everconfirmed($self, @_)
+}
+
+sub everconfirmed {
+ my $self = shift;
+ return ($self->{'status'} == 'UNCONFIRMED') ? 0 : 1;
+}
+
+1;
+
diff --git a/extensions/BMO/lib/Reports/EmailQueue.pm b/extensions/BMO/lib/Reports/EmailQueue.pm
new file mode 100644
index 000000000..f1383aac7
--- /dev/null
+++ b/extensions/BMO/lib/Reports/EmailQueue.pm
@@ -0,0 +1,84 @@
+# 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.
+
+package Bugzilla::Extension::BMO::Reports::EmailQueue;
+use strict;
+use warnings;
+
+use Bugzilla::Error;
+use Scalar::Util qw(blessed);
+use Storable ();
+
+sub report {
+ my ($vars, $filter) = @_;
+ my $dbh = Bugzilla->dbh;
+ my $user = Bugzilla->user;
+
+ $user->in_group('admin') || $user->in_group('infra')
+ || ThrowUserError('auth_failure', { group => 'admin',
+ action => 'run',
+ object => 'email_queue' });
+
+ my $query = "
+ SELECT j.jobid,
+ j.arg,
+ j.insert_time,
+ j.run_after AS run_time,
+ COUNT(e.jobid) AS error_count,
+ MAX(e.error_time) AS error_time,
+ e.message AS error_message
+ FROM ts_job j
+ LEFT JOIN ts_error e ON e.jobid = j.jobid
+ GROUP BY j.jobid
+ ORDER BY j.run_after";
+
+ $vars->{'jobs'} = $dbh->selectall_arrayref($query, { Slice => {} });
+ foreach my $job (@{ $vars->{'jobs'} }) {
+ eval {
+ my ($recipient, $description);
+ my $arg = _cond_thaw(delete $job->{arg});
+
+ if (exists $arg->{vars}) {
+ my $vars = $arg->{vars};
+ $recipient = $vars->{to_user}->{login_name};
+ $description = '[Bug ' . $vars->{bug}->{bug_id} . '] ' . $vars->{bug}->{short_desc};
+ } elsif (exists $arg->{msg}) {
+ my $msg = $arg->{msg};
+ if (ref($msg) && blessed($msg) eq 'Email::MIME') {
+ $recipient = $msg->header('to');
+ $description = $msg->header('subject');
+ } else {
+ ($recipient) = $msg =~ /\nTo: ([^\n]+)/;
+ ($description) = $msg =~ /\nSubject: ([^\n]+)/;
+ }
+ }
+
+ if ($recipient) {
+ $job->{subject} = "<$recipient> $description";
+ }
+ };
+ }
+ $vars->{'now'} = (time);
+}
+
+sub _cond_thaw {
+ my $data = shift;
+ my $magic = eval { Storable::read_magic($data); };
+ if ($magic && $magic->{major} && $magic->{major} >= 2 && $magic->{major} <= 5) {
+ my $thawed = eval { Storable::thaw($data) };
+ if ($@) {
+ # false alarm... looked like a Storable, but wasn't.
+ return $data;
+ }
+ return $thawed;
+ } else {
+ return $data;
+ }
+}
+
+
+1;
diff --git a/extensions/BMO/lib/Reports/Groups.pm b/extensions/BMO/lib/Reports/Groups.pm
new file mode 100644
index 000000000..ab0f1efa4
--- /dev/null
+++ b/extensions/BMO/lib/Reports/Groups.pm
@@ -0,0 +1,243 @@
+# 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.
+
+package Bugzilla::Extension::BMO::Reports::Groups;
+use strict;
+use warnings;
+
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Group;
+use Bugzilla::User;
+use Bugzilla::Util qw(trim);
+
+sub admins_report {
+ my ($vars) = @_;
+ my $dbh = Bugzilla->dbh;
+ my $user = Bugzilla->user;
+
+ ($user->in_group('editusers') || $user->in_group('infrasec'))
+ || ThrowUserError('auth_failure', { group => 'editusers',
+ action => 'run',
+ object => 'group_admins' });
+
+ my $query = "
+ SELECT groups.name, " .
+ $dbh->sql_group_concat('profiles.login_name', "','", 1) . "
+ FROM groups
+ LEFT JOIN user_group_map
+ ON user_group_map.group_id = groups.id
+ AND user_group_map.isbless = 1
+ AND user_group_map.grant_type = 0
+ LEFT JOIN profiles
+ ON user_group_map.user_id = profiles.userid
+ WHERE groups.isbuggroup = 1
+ GROUP BY groups.name";
+
+ my @groups;
+ foreach my $group (@{ $dbh->selectall_arrayref($query) }) {
+ my @admins;
+ if ($group->[1]) {
+ foreach my $admin (split(/,/, $group->[1])) {
+ push(@admins, Bugzilla::User->new({ name => $admin }));
+ }
+ }
+ push(@groups, { name => $group->[0], admins => \@admins });
+ }
+
+ $vars->{'groups'} = \@groups;
+}
+
+sub membership_report {
+ my ($page, $vars) = @_;
+ my $dbh = Bugzilla->dbh;
+ my $user = Bugzilla->user;
+ my $cgi = Bugzilla->cgi;
+
+ ($user->in_group('editusers') || $user->in_group('infrasec'))
+ || ThrowUserError('auth_failure', { group => 'editusers',
+ action => 'run',
+ object => 'group_admins' });
+
+ my $who = $cgi->param('who');
+ if (!defined($who) || $who eq '') {
+ if ($page eq 'group_membership.txt') {
+ print $cgi->redirect("page.cgi?id=group_membership.html&output=txt");
+ exit;
+ }
+ $vars->{'output'} = $cgi->param('output');
+ return;
+ }
+
+ Bugzilla::User::match_field({ 'who' => {'type' => 'multi'} });
+ $who = Bugzilla->input_params->{'who'};
+ $who = ref($who) ? $who : [ $who ];
+
+ my @users;
+ foreach my $login (@$who) {
+ my $u = Bugzilla::User->new(login_to_id($login, 1));
+
+ # this is lifted from $user->groups()
+ # we need to show which groups are direct and which are inherited
+
+ my $groups_to_check = $dbh->selectcol_arrayref(
+ q{SELECT DISTINCT group_id
+ FROM user_group_map
+ WHERE user_id = ? AND isbless = 0}, undef, $u->id);
+
+ my $rows = $dbh->selectall_arrayref(
+ "SELECT DISTINCT grantor_id, member_id
+ FROM group_group_map
+ WHERE grant_type = " . GROUP_MEMBERSHIP);
+
+ my %group_membership;
+ foreach my $row (@$rows) {
+ my ($grantor_id, $member_id) = @$row;
+ push (@{ $group_membership{$member_id} }, $grantor_id);
+ }
+
+ my %checked_groups;
+ my %direct_groups;
+ my %indirect_groups;
+ my %groups;
+
+ foreach my $member_id (@$groups_to_check) {
+ $direct_groups{$member_id} = 1;
+ }
+
+ while (scalar(@$groups_to_check) > 0) {
+ my $member_id = shift @$groups_to_check;
+ if (!$checked_groups{$member_id}) {
+ $checked_groups{$member_id} = 1;
+ my $members = $group_membership{$member_id};
+ my @new_to_check = grep(!$checked_groups{$_}, @$members);
+ push(@$groups_to_check, @new_to_check);
+ foreach my $id (@new_to_check) {
+ $indirect_groups{$id} = $member_id;
+ }
+ $groups{$member_id} = 1;
+ }
+ }
+
+ my @groups;
+ my $ra_groups = Bugzilla::Group->new_from_list([keys %groups]);
+ foreach my $group (@$ra_groups) {
+ my $via;
+ if ($direct_groups{$group->id}) {
+ $via = '';
+ } else {
+ foreach my $g (@$ra_groups) {
+ if ($g->id == $indirect_groups{$group->id}) {
+ $via = $g->name;
+ last;
+ }
+ }
+ }
+ push @groups, {
+ name => $group->name,
+ desc => $group->description,
+ via => $via,
+ };
+ }
+
+ push @users, {
+ user => $u,
+ groups => \@groups,
+ };
+ }
+
+ $vars->{'who'} = $who;
+ $vars->{'users'} = \@users;
+}
+
+sub members_report {
+ my ($vars) = @_;
+ my $dbh = Bugzilla->dbh;
+ my $user = Bugzilla->user;
+ my $cgi = Bugzilla->cgi;
+
+ ($user->in_group('editusers') || $user->in_group('infrasec'))
+ || ThrowUserError('auth_failure', { group => 'editusers',
+ action => 'run',
+ object => 'group_admins' });
+
+ my $include_disabled = $cgi->param('include_disabled') ? 1 : 0;
+ $vars->{'include_disabled'} = $include_disabled;
+
+ # don't allow all groups, to avoid putting pain on the servers
+ my @group_names =
+ sort
+ grep { !/^(?:bz_.+|canconfirm|editbugs|editbugs-team|everyone)$/ }
+ map { lc($_->name) }
+ Bugzilla::Group->get_all;
+ unshift(@group_names, '');
+ $vars->{'groups'} = \@group_names;
+
+ # load selected group
+ my $group = lc(trim($cgi->param('group') || ''));
+ $group = '' unless grep { $_ eq $group } @group_names;
+ return if $group eq '';
+ my $group_obj = Bugzilla::Group->new({ name => $group });
+ $vars->{'group'} = $group;
+
+ # direct members
+ my @types = (
+ {
+ name => 'direct',
+ members => _filter_userlist($group_obj->members_direct, $include_disabled),
+ },
+ );
+
+ # indirect members, by group
+ foreach my $member_group (sort @{ $group_obj->grant_direct(GROUP_MEMBERSHIP) }) {
+ push @types, {
+ name => $member_group->name,
+ members => _filter_userlist($member_group->members_direct, $include_disabled),
+ },
+ }
+
+ # make it easy for the template to detect an empty group
+ my $has_members = 0;
+ foreach my $type (@types) {
+ $has_members += scalar(@{ $type->{members} });
+ last if $has_members;
+ }
+ @types = () unless $has_members;
+
+ if (@types) {
+ # add last-login
+ my $user_ids = join(',', map { map { $_->id } @{ $_->{members} } } @types);
+ my $tokens = $dbh->selectall_hashref("
+ SELECT profiles.userid,
+ (SELECT DATEDIFF(curdate(), logincookies.lastused) lastseen
+ FROM logincookies
+ WHERE logincookies.userid = profiles.userid
+ ORDER BY lastused DESC
+ LIMIT 1) lastseen
+ FROM profiles
+ WHERE userid IN ($user_ids)",
+ 'userid');
+ foreach my $type (@types) {
+ foreach my $member (@{ $type->{members} }) {
+ $member->{lastseen} =
+ defined $tokens->{$member->id}->{lastseen}
+ ? $tokens->{$member->id}->{lastseen}
+ : '>' . MAX_LOGINCOOKIE_AGE;
+ }
+ }
+ }
+
+ $vars->{'types'} = \@types;
+}
+
+sub _filter_userlist {
+ my ($list, $include_disabled) = @_;
+ $list = [ grep { $_->is_enabled } @$list ] unless $include_disabled;
+ return [ sort { lc($a->identity) cmp lc($b->identity) } @$list ];
+}
+
+1;
diff --git a/extensions/BMO/lib/Reports/ProductSecurity.pm b/extensions/BMO/lib/Reports/ProductSecurity.pm
new file mode 100644
index 000000000..2324e725a
--- /dev/null
+++ b/extensions/BMO/lib/Reports/ProductSecurity.pm
@@ -0,0 +1,67 @@
+# 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.
+
+package Bugzilla::Extension::BMO::Reports::ProductSecurity;
+use strict;
+use warnings;
+
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Product;
+
+sub report {
+ my ($vars) = @_;
+ my $user = Bugzilla->user;
+
+ ($user->in_group('admin') || $user->in_group('infrasec'))
+ || ThrowUserError('auth_failure', { group => 'admin',
+ action => 'run',
+ object => 'product_security' });
+
+ my $moco = Bugzilla::Group->new({ name => 'mozilla-employee-confidential' })
+ or return;
+
+ my $products = [];
+ foreach my $product (@{ Bugzilla::Product->match({}) }) {
+ my $default_group = $product->default_security_group_obj;
+ my $group_controls = $product->group_controls();
+
+ my $item = {
+ name => $product->name,
+ default_security_group => $product->default_security_group,
+ group_visibility => 'None/None',
+ moco => exists $group_controls->{$moco->id},
+ };
+
+ if ($default_group) {
+ if (my $control = $group_controls->{$default_group->id}) {
+ $item->{group_visibility} = control_to_string($control->{membercontrol}) .
+ '/' . control_to_string($control->{othercontrol});
+ }
+ }
+
+ $item->{group_problem} = $default_group ? '' : "Invalid group " . $product->default_security_group;
+ $item->{visibility_problem} = 'Default security group should be Shown/Shown'
+ if ($item->{group_visibility} ne 'Shown/Shown')
+ && ($item->{group_visibility} ne 'Mandatory/Mandatory')
+ && ($item->{group_visibility} ne 'Default/Default');
+
+ push @$products, $item;
+ }
+ $vars->{products} = $products;
+}
+
+sub control_to_string {
+ my ($control) = @_;
+ return 'NA' if $control == CONTROLMAPNA;
+ return 'Shown' if $control == CONTROLMAPSHOWN;
+ return 'Default' if $control == CONTROLMAPDEFAULT;
+ return 'Mandatory' if $control == CONTROLMAPMANDATORY;
+ return '';
+}
+
+1;
diff --git a/extensions/BMO/lib/Reports/ReleaseTracking.pm b/extensions/BMO/lib/Reports/ReleaseTracking.pm
new file mode 100644
index 000000000..5a07ae196
--- /dev/null
+++ b/extensions/BMO/lib/Reports/ReleaseTracking.pm
@@ -0,0 +1,409 @@
+# 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.
+
+package Bugzilla::Extension::BMO::Reports::ReleaseTracking;
+use strict;
+use warnings;
+
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Extension::BMO::Util;
+use Bugzilla::Field;
+use Bugzilla::FlagType;
+use Bugzilla::Util qw(correct_urlbase trick_taint);
+use JSON qw(-convert_blessed_universally);
+use List::MoreUtils qw(uniq);
+
+sub report {
+ my ($vars) = @_;
+ my $dbh = Bugzilla->dbh;
+ my $input = Bugzilla->input_params;
+ my $user = Bugzilla->user;
+
+ my @flag_names = qw(
+ approval-mozilla-release
+ approval-mozilla-beta
+ approval-mozilla-aurora
+ approval-mozilla-central
+ approval-comm-release
+ approval-comm-beta
+ approval-comm-aurora
+ approval-calendar-release
+ approval-calendar-beta
+ approval-calendar-aurora
+ approval-mozilla-esr10
+ );
+
+ my @flags_json;
+ my @fields_json;
+ my @products_json;
+
+ #
+ # tracking flags
+ #
+
+ my $all_products = $user->get_selectable_products;
+ my @usable_products;
+
+ # build list of flags and their matching products
+
+ my @invalid_flag_names;
+ foreach my $flag_name (@flag_names) {
+ # grab all matching flag_types
+ my @flag_types = @{Bugzilla::FlagType::match({ name => $flag_name, is_active => 1 })};
+
+ # remove invalid flags
+ if (!@flag_types) {
+ push @invalid_flag_names, $flag_name;
+ next;
+ }
+
+ # we need a list of products, based on inclusions/exclusions
+ my @products;
+ my %flag_types;
+ foreach my $flag_type (@flag_types) {
+ $flag_types{$flag_type->name} = $flag_type->id;
+ my $has_all = 0;
+ my @exclusion_ids;
+ my @inclusion_ids;
+ foreach my $flag_type (@flag_types) {
+ if (scalar keys %{$flag_type->inclusions}) {
+ my $inclusions = $flag_type->inclusions;
+ foreach my $key (keys %$inclusions) {
+ push @inclusion_ids, ($inclusions->{$key} =~ /^(\d+)/);
+ }
+ } elsif (scalar keys %{$flag_type->exclusions}) {
+ my $exclusions = $flag_type->exclusions;
+ foreach my $key (keys %$exclusions) {
+ push @exclusion_ids, ($exclusions->{$key} =~ /^(\d+)/);
+ }
+ } else {
+ $has_all = 1;
+ last;
+ }
+ }
+
+ if ($has_all) {
+ push @products, @$all_products;
+ } elsif (scalar @exclusion_ids) {
+ push @products, @$all_products;
+ foreach my $exclude_id (uniq @exclusion_ids) {
+ @products = grep { $_->id != $exclude_id } @products;
+ }
+ } else {
+ foreach my $include_id (uniq @inclusion_ids) {
+ push @products, grep { $_->id == $include_id } @$all_products;
+ }
+ }
+ }
+ @products = uniq @products;
+ push @usable_products, @products;
+ my @product_ids = map { $_->id } sort { lc($a->name) cmp lc($b->name) } @products;
+
+ push @flags_json, {
+ name => $flag_name,
+ id => $flag_types{$flag_name} || 0,
+ products => \@product_ids,
+ fields => [],
+ };
+ }
+ foreach my $flag_name (@invalid_flag_names) {
+ @flag_names = grep { $_ ne $flag_name } @flag_names;
+ }
+ @usable_products = uniq @usable_products;
+
+ # build a list of tracking flags for each product
+ # also build the list of all fields
+
+ my @unlink_products;
+ foreach my $product (@usable_products) {
+ my @fields =
+ grep { is_active_status_field($_) }
+ Bugzilla->active_custom_fields({ product => $product });
+ my @field_ids = map { $_->id } @fields;
+ if (!scalar @fields) {
+ push @unlink_products, $product;
+ next;
+ }
+
+ # product
+ push @products_json, {
+ name => $product->name,
+ id => $product->id,
+ fields => \@field_ids,
+ };
+
+ # add fields to flags
+ foreach my $rh (@flags_json) {
+ if (grep { $_ eq $product->id } @{$rh->{products}}) {
+ push @{$rh->{fields}}, @field_ids;
+ }
+ }
+
+ # add fields to fields_json
+ foreach my $field (@fields) {
+ my $existing = 0;
+ foreach my $rh (@fields_json) {
+ if ($rh->{id} == $field->id) {
+ $existing = 1;
+ last;
+ }
+ }
+ if (!$existing) {
+ push @fields_json, {
+ name => $field->name,
+ id => $field->id,
+ };
+ }
+ }
+ }
+ foreach my $rh (@flags_json) {
+ my @fields = uniq @{$rh->{fields}};
+ $rh->{fields} = \@fields;
+ }
+
+ # remove products which aren't linked with status fields
+
+ foreach my $rh (@flags_json) {
+ my @product_ids;
+ foreach my $id (@{$rh->{products}}) {
+ unless (grep { $_->id == $id } @unlink_products) {
+ push @product_ids, $id;
+ }
+ $rh->{products} = \@product_ids;
+ }
+ }
+
+ #
+ # rapid release dates
+ #
+
+ my @ranges;
+ my $start_date = string_to_datetime('2011-08-16');
+ my $end_date = $start_date->clone->add(weeks => 6)->add(days => -1);
+ my $now_date = string_to_datetime('2012-11-19');
+
+ while ($start_date <= $now_date) {
+ unshift @ranges, {
+ value => sprintf("%s-%s", $start_date->ymd(''), $end_date->ymd('')),
+ label => sprintf("%s and %s", $start_date->ymd('-'), $end_date->ymd('-')),
+ };
+
+ $start_date = $end_date->clone;;
+ $start_date->add(days => 1);
+ $end_date->add(weeks => 6);
+ }
+
+ # 2012-11-20 - 2013-01-06 was a 7 week release cycle instead of 6
+ $start_date = string_to_datetime('2012-11-20');
+ $end_date = $start_date->clone->add(weeks => 7)->add(days => -1);
+ unshift @ranges, {
+ value => sprintf("%s-%s", $start_date->ymd(''), $end_date->ymd('')),
+ label => sprintf("%s and %s", $start_date->ymd('-'), $end_date->ymd('-')),
+ };
+
+ # Back on track with 6 week releases
+ $start_date = string_to_datetime('2013-01-08');
+ $end_date = $start_date->clone->add(weeks => 6)->add(days => -1);
+ $now_date = time_to_datetime((time));
+
+ while ($start_date <= $now_date) {
+ unshift @ranges, {
+ value => sprintf("%s-%s", $start_date->ymd(''), $end_date->ymd('')),
+ label => sprintf("%s and %s", $start_date->ymd('-'), $end_date->ymd('-')),
+ };
+
+ $start_date = $end_date->clone;;
+ $start_date->add(days => 1);
+ $end_date->add(weeks => 6);
+ }
+
+ push @ranges, {
+ value => '*',
+ label => 'Anytime',
+ };
+
+ #
+ # run report
+ #
+
+ if ($input->{q} && !$input->{edit}) {
+ my $q = _parse_query($input->{q});
+
+ my @where;
+ my @params;
+ my $query = "
+ SELECT DISTINCT b.bug_id
+ FROM bugs b
+ INNER JOIN flags f ON f.bug_id = b.bug_id ";
+
+ if ($q->{start_date}) {
+ $query .= "INNER JOIN bugs_activity a ON a.bug_id = b.bug_id ";
+ }
+
+ if (grep($_ == FIELD_TYPE_EXTENSION, map { $_->{type} } @{ $q->{fields} })) {
+ $query .= "LEFT JOIN tracking_flags_bugs AS tfb ON tfb.bug_id = b.bug_id " .
+ "LEFT JOIN tracking_flags AS tf ON tfb.tracking_flag_id = tf.id ";
+ }
+
+ $query .= "WHERE ";
+
+ if ($q->{start_date}) {
+ push @where, "(a.fieldid = ?)";
+ push @params, $q->{field_id};
+
+ push @where, "(a.bug_when >= ?)";
+ push @params, $q->{start_date} . ' 00:00:00';
+ push @where, "(a.bug_when < ?)";
+ push @params, $q->{end_date} . ' 00:00:00';
+
+ push @where, "(a.added LIKE ?)";
+ push @params, '%' . $q->{flag_name} . $q->{flag_status} . '%';
+ }
+
+ my ($type_id) = $dbh->selectrow_array(
+ "SELECT id FROM flagtypes WHERE name = ?",
+ undef,
+ $q->{flag_name}
+ );
+ push @where, "(f.type_id = ?)";
+ push @params, $type_id;
+
+ push @where, "(f.status = ?)";
+ push @params, $q->{flag_status};
+
+ if ($q->{product_id}) {
+ push @where, "(b.product_id = ?)";
+ push @params, $q->{product_id};
+ }
+
+ if (scalar @{$q->{fields}}) {
+ my @fields;
+ foreach my $field (@{$q->{fields}}) {
+ my $field_sql = "(";
+ if ($field->{type} == FIELD_TYPE_EXTENSION) {
+ $field_sql .= "tf.name = " . $dbh->quote($field->{name}) . " AND COALESCE(tfb.value, '')";
+ }
+ else {
+ $field_sql .= "b." . $field->{name};
+ }
+ $field_sql .= " " . ($field->{value} eq '+' ? '' : 'NOT ') . "IN ('fixed','verified'))";
+ push(@fields, $field_sql);
+ }
+ my $join = uc $q->{join};
+ push @where, '(' . join(" $join ", @fields) . ')';
+ }
+
+ $query .= join("\nAND ", @where);
+
+ if ($input->{debug}) {
+ print "Content-Type: text/plain\n\n";
+ $query =~ s/\?/\000/g;
+ foreach my $param (@params) {
+ $query =~ s/\000/'$param'/;
+ }
+ print "$query\n";
+ exit;
+ }
+
+ my $bugs = $dbh->selectcol_arrayref($query, undef, @params);
+ push @$bugs, 0 unless @$bugs;
+
+ my $urlbase = correct_urlbase();
+ my $cgi = Bugzilla->cgi;
+ print $cgi->redirect(
+ -url => "${urlbase}buglist.cgi?bug_id=" . join(',', @$bugs)
+ );
+ exit;
+ }
+
+ #
+ # set template vars
+ #
+
+ my $json = JSON->new();
+ if (0) {
+ # debugging
+ $json->shrink(0);
+ $json->canonical(1);
+ $vars->{flags_json} = $json->pretty->encode(\@flags_json);
+ $vars->{products_json} = $json->pretty->encode(\@products_json);
+ $vars->{fields_json} = $json->pretty->encode(\@fields_json);
+ } else {
+ $json->shrink(1);
+ $vars->{flags_json} = $json->encode(\@flags_json);
+ $vars->{products_json} = $json->encode(\@products_json);
+ $vars->{fields_json} = $json->encode(\@fields_json);
+ }
+
+ $vars->{flag_names} = \@flag_names;
+ $vars->{ranges} = \@ranges;
+ $vars->{default_query} = $input->{q};
+ foreach my $field (qw(product flags range)) {
+ $vars->{$field} = $input->{$field};
+ }
+}
+
+sub _parse_query {
+ my $q = shift;
+ my @query = split(/:/, $q);
+ my $query;
+
+ # field_id for flag changes
+ $query->{field_id} = get_field_id('flagtypes.name');
+
+ # flag_name
+ my $flag_name = shift @query;
+ @{Bugzilla::FlagType::match({ name => $flag_name, is_active => 1 })}
+ or ThrowUserError('report_invalid_parameter', { name => 'flag_name' });
+ trick_taint($flag_name);
+ $query->{flag_name} = $flag_name;
+
+ # flag_status
+ my $flag_status = shift @query;
+ $flag_status =~ /^([\?\-\+])$/
+ or ThrowUserError('report_invalid_parameter', { name => 'flag_status' });
+ $query->{flag_status} = $1;
+
+ # date_range -> from_ymd to_ymd
+ my $date_range = shift @query;
+ if ($date_range ne '*') {
+ $date_range =~ /^(\d\d\d\d)(\d\d)(\d\d)-(\d\d\d\d)(\d\d)(\d\d)$/
+ or ThrowUserError('report_invalid_parameter', { name => 'date_range' });
+ $query->{start_date} = "$1-$2-$3";
+ $query->{end_date} = "$4-$5-$6";
+ }
+
+ # product_id
+ my $product_id = shift @query;
+ $product_id =~ /^(\d+)$/
+ or ThrowUserError('report_invalid_parameter', { name => 'product_id' });
+ $query->{product_id} = $1;
+
+ # join
+ my $join = shift @query;
+ $join =~ /^(and|or)$/
+ or ThrowUserError('report_invalid_parameter', { name => 'join' });
+ $query->{join} = $1;
+
+ # fields
+ my @fields;
+ foreach my $field (@query) {
+ $field =~ /^(\d+)([\-\+])$/
+ or ThrowUserError('report_invalid_parameter', { name => 'fields' });
+ my ($id, $value) = ($1, $2);
+ my $field_obj = Bugzilla::Field->new($id)
+ or ThrowUserError('report_invalid_parameter', { name => 'field_id' });
+ push @fields, { id => $id, value => $value,
+ name => $field_obj->name, type => $field_obj->type };
+ }
+ $query->{fields} = \@fields;
+
+ return $query;
+}
+
+1;
diff --git a/extensions/BMO/lib/Reports/Triage.pm b/extensions/BMO/lib/Reports/Triage.pm
new file mode 100644
index 000000000..debb50577
--- /dev/null
+++ b/extensions/BMO/lib/Reports/Triage.pm
@@ -0,0 +1,217 @@
+# 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.
+
+package Bugzilla::Extension::BMO::Reports::Triage;
+use strict;
+
+use Bugzilla::Component;
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Product;
+use Bugzilla::User;
+use Bugzilla::Util qw(detaint_natural);
+use Date::Parse;
+
+# set an upper limit on the *unfiltered* number of bugs to process
+use constant MAX_NUMBER_BUGS => 4000;
+
+sub report {
+ my ($vars, $filter) = @_;
+ my $dbh = Bugzilla->dbh;
+ my $input = Bugzilla->input_params;
+ my $user = Bugzilla->user;
+
+ if (exists $input->{'action'} && $input->{'action'} eq 'run' && $input->{'product'}) {
+
+ # load product and components from input
+
+ my $product = Bugzilla::Product->new({ name => $input->{'product'} })
+ || ThrowUserError('invalid_object', { object => 'Product', value => $input->{'product'} });
+
+ my @component_ids;
+ if ($input->{'component'} ne '') {
+ my $ra_components = ref($input->{'component'})
+ ? $input->{'component'} : [ $input->{'component'} ];
+ foreach my $component_name (@$ra_components) {
+ my $component = Bugzilla::Component->new({ name => $component_name, product => $product })
+ || ThrowUserError('invalid_object', { object => 'Component', value => $component_name });
+ push @component_ids, $component->id;
+ }
+ }
+
+ # determine which comment filters to run
+
+ my $filter_commenter = $input->{'filter_commenter'};
+ my $filter_commenter_on = $input->{'commenter'};
+ my $filter_last = $input->{'filter_last'};
+ my $filter_last_period = $input->{'last'};
+
+ if (!$filter_commenter || $filter_last) {
+ $filter_commenter = '1';
+ $filter_commenter_on = 'reporter';
+ }
+
+ my $filter_commenter_id;
+ if ($filter_commenter && $filter_commenter_on eq 'is') {
+ Bugzilla::User::match_field({ 'commenter_is' => {'type' => 'single'} });
+ my $user = Bugzilla::User->new({ name => $input->{'commenter_is'} })
+ || ThrowUserError('invalid_object', { object => 'User', value => $input->{'commenter_is'} });
+ $filter_commenter_id = $user ? $user->id : 0;
+ }
+
+ my $filter_last_time;
+ if ($filter_last) {
+ if ($filter_last_period eq 'is') {
+ $filter_last_period = -1;
+ $filter_last_time = str2time($input->{'last_is'} . " 00:00:00") || 0;
+ } else {
+ detaint_natural($filter_last_period);
+ $filter_last_period = 14 if $filter_last_period < 14;
+ }
+ }
+
+ # form sql queries
+
+ my $now = (time);
+ my $bugs_sql = "
+ SELECT bug_id, short_desc, reporter, creation_ts
+ FROM bugs
+ WHERE product_id = ?
+ AND bug_status = 'UNCONFIRMED'";
+ if (@component_ids) {
+ $bugs_sql .= " AND component_id IN (" . join(',', @component_ids) . ")";
+ }
+ $bugs_sql .= "
+ ORDER BY creation_ts
+ ";
+
+ my $comment_count_sql = "
+ SELECT COUNT(*)
+ FROM longdescs
+ WHERE bug_id = ?
+ ";
+
+ my $comment_sql = "
+ SELECT who, bug_when, type, thetext, extra_data
+ FROM longdescs
+ WHERE bug_id = ?
+ ";
+ if (!Bugzilla->user->is_insider) {
+ $comment_sql .= " AND isprivate = 0 ";
+ }
+ $comment_sql .= "
+ ORDER BY bug_when DESC
+ LIMIT 1
+ ";
+
+ my $attach_sql = "
+ SELECT description, isprivate
+ FROM attachments
+ WHERE attach_id = ?
+ ";
+
+ # work on an initial list of bugs
+
+ my $list = $dbh->selectall_arrayref($bugs_sql, undef, $product->id);
+ my @bugs;
+
+ # this can be slow to process, resulting in 'service unavailable' errors from zeus
+ # so if too many bugs are returned, throw an error
+
+ if (scalar(@$list) > MAX_NUMBER_BUGS) {
+ ThrowUserError('report_too_many_bugs');
+ }
+
+ foreach my $entry (@$list) {
+ my ($bug_id, $summary, $reporter_id, $creation_ts) = @$entry;
+
+ next unless $user->can_see_bug($bug_id);
+
+ # get last comment information
+
+ my ($comment_count) = $dbh->selectrow_array($comment_count_sql, undef, $bug_id);
+ my ($commenter_id, $comment_ts, $type, $comment, $extra)
+ = $dbh->selectrow_array($comment_sql, undef, $bug_id);
+ my $commenter = 0;
+
+ # apply selected filters
+
+ if ($filter_commenter) {
+ next if $comment_count <= 1;
+
+ if ($filter_commenter_on eq 'reporter') {
+ next if $commenter_id != $reporter_id;
+
+ } elsif ($filter_commenter_on eq 'noconfirm') {
+ $commenter = Bugzilla::User->new({ id => $commenter_id, cache => 1 });
+ next if $commenter_id != $reporter_id
+ || $commenter->in_group('canconfirm');
+
+ } elsif ($filter_commenter_on eq 'is') {
+ next if $commenter_id != $filter_commenter_id;
+ }
+ } else {
+ $input->{'commenter'} = '';
+ $input->{'commenter_is'} = '';
+ }
+
+ if ($filter_last) {
+ my $comment_time = str2time($comment_ts)
+ or next;
+ if ($filter_last_period == -1) {
+ next if $comment_time >= $filter_last_time;
+ } else {
+ next if $now - $comment_time <= 60 * 60 * 24 * $filter_last_period;
+ }
+ } else {
+ $input->{'last'} = '';
+ $input->{'last_is'} = '';
+ }
+
+ # get data for attachment comments
+
+ if ($comment eq '' && $type == CMT_ATTACHMENT_CREATED) {
+ my ($description, $is_private) = $dbh->selectrow_array($attach_sql, undef, $extra);
+ next if $is_private && !Bugzilla->user->is_insider;
+ $comment = "(Attachment) " . $description;
+ }
+
+ # truncate long comments
+
+ if (length($comment) > 80) {
+ $comment = substr($comment, 0, 80) . '...';
+ }
+
+ # build bug hash for template
+
+ my $bug = {};
+ $bug->{id} = $bug_id;
+ $bug->{summary} = $summary;
+ $bug->{reporter} = Bugzilla::User->new({ id => $reporter_id, cache => 1 });
+ $bug->{creation_ts} = $creation_ts;
+ $bug->{commenter} = $commenter || Bugzilla::User->new({ id => $commenter_id, cache => 1 });
+ $bug->{comment_ts} = $comment_ts;
+ $bug->{comment} = $comment;
+ $bug->{comment_count} = $comment_count;
+ push @bugs, $bug;
+ }
+
+ @bugs = sort { $b->{comment_ts} cmp $a->{comment_ts} } @bugs;
+
+ $vars->{bugs} = \@bugs;
+ } else {
+ $input->{action} = '';
+ }
+
+ if (!$input->{filter_commenter} && !$input->{filter_last}) {
+ $input->{filter_commenter} = 1;
+ }
+
+ $vars->{'input'} = $input;
+}
+
+1;
diff --git a/extensions/BMO/lib/Reports/UserActivity.pm b/extensions/BMO/lib/Reports/UserActivity.pm
new file mode 100644
index 000000000..04810c2ec
--- /dev/null
+++ b/extensions/BMO/lib/Reports/UserActivity.pm
@@ -0,0 +1,327 @@
+# 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.
+
+package Bugzilla::Extension::BMO::Reports::UserActivity;
+use strict;
+use warnings;
+
+use Bugzilla::Error;
+use Bugzilla::Extension::BMO::Util;
+use Bugzilla::User;
+use Bugzilla::Util qw(trim);
+use DateTime;
+
+sub report {
+ my ($vars) = @_;
+ my $dbh = Bugzilla->dbh;
+ my $input = Bugzilla->input_params;
+
+ my @who = ();
+ my $from = trim($input->{'from'} || '');
+ my $to = trim($input->{'to'} || '');
+ my $action = $input->{'action'} || '';
+
+ # fix non-breaking hyphens
+ $from =~ s/\N{U+2011}/-/g;
+ $to =~ s/\N{U+2011}/-/g;
+
+ if ($from eq '') {
+ my $dt = DateTime->now()->subtract('weeks' => 1);
+ $from = $dt->ymd('-');
+ }
+ if ($to eq '') {
+ my $dt = DateTime->now();
+ $to = $dt->ymd('-');
+ }
+
+ if ($action eq 'run') {
+ if (!exists $input->{'who'} || $input->{'who'} eq '') {
+ ThrowUserError('user_activity_missing_username');
+ }
+ Bugzilla::User::match_field({ 'who' => {'type' => 'multi'} });
+
+ my $from_dt = string_to_datetime($from);
+ $from = $from_dt->ymd();
+
+ my $to_dt = string_to_datetime($to);
+ $to = $to_dt->ymd();
+
+ my ($activity_joins, $activity_where) = ('', '');
+ my ($attachments_joins, $attachments_where) = ('', '');
+ my ($tags_activity_joins, $tags_activity_where) = ('', '');
+ if (Bugzilla->params->{"insidergroup"}
+ && !Bugzilla->user->in_group(Bugzilla->params->{'insidergroup'}))
+ {
+ $activity_joins = "LEFT JOIN attachments
+ ON attachments.attach_id = bugs_activity.attach_id";
+ $activity_where = "AND COALESCE(attachments.isprivate, 0) = 0";
+ $attachments_where = $activity_where;
+
+ $tags_activity_joins = 'LEFT JOIN longdescs
+ ON longdescs_tags_activity.comment_id = longdescs.comment_id';
+ $tags_activity_where = 'AND COALESCE(longdescs.isprivate, 0) = 0';
+ }
+
+ my @who_bits;
+ foreach my $who (
+ ref $input->{'who'}
+ ? @{$input->{'who'}}
+ : $input->{'who'}
+ ) {
+ push @who, $who;
+ push @who_bits, '?';
+ }
+ my $who_bits = join(',', @who_bits);
+
+ if (!@who) {
+ my $template = Bugzilla->template;
+ my $cgi = Bugzilla->cgi;
+ my $vars = {};
+ $vars->{'script'} = $cgi->url(-relative => 1);
+ $vars->{'fields'} = {};
+ $vars->{'matches'} = [];
+ $vars->{'matchsuccess'} = 0;
+ $vars->{'matchmultiple'} = 1;
+ print $cgi->header();
+ $template->process("global/confirm-user-match.html.tmpl", $vars)
+ || ThrowTemplateError($template->error());
+ exit;
+ }
+
+ $from_dt = $from_dt->ymd() . ' 00:00:00';
+ $to_dt = $to_dt->ymd() . ' 23:59:59';
+ my @params;
+ for (1..5) {
+ push @params, @who;
+ push @params, ($from_dt, $to_dt);
+ }
+
+ my $order = ($input->{'group'} && $input->{'group'} eq 'bug')
+ ? 'bug_id, bug_when' : 'bug_when';
+
+ my $comment_filter = '';
+ if (!Bugzilla->user->is_insider) {
+ $comment_filter = 'AND longdescs.isprivate = 0';
+ }
+
+ my $query = "
+ SELECT
+ fielddefs.name,
+ bugs_activity.bug_id,
+ bugs_activity.attach_id,
+ ".$dbh->sql_date_format('bugs_activity.bug_when', '%Y.%m.%d %H:%i:%s')." AS ts,
+ bugs_activity.removed,
+ bugs_activity.added,
+ profiles.login_name,
+ bugs_activity.comment_id,
+ bugs_activity.bug_when
+ FROM bugs_activity
+ $activity_joins
+ LEFT JOIN fielddefs
+ ON bugs_activity.fieldid = fielddefs.id
+ INNER JOIN profiles
+ ON profiles.userid = bugs_activity.who
+ WHERE profiles.login_name IN ($who_bits)
+ AND bugs_activity.bug_when >= ? AND bugs_activity.bug_when <= ?
+ $activity_where
+
+ UNION ALL
+
+ SELECT
+ 'comment_tag' AS name,
+ longdescs_tags_activity.bug_id,
+ NULL as attach_id,
+ ".$dbh->sql_date_format('longdescs_tags_activity.bug_when',
+ '%Y.%m.%d %H:%i:%s') . " AS bug_when,
+ longdescs_tags_activity.removed,
+ longdescs_tags_activity.added,
+ profiles.login_name,
+ longdescs_tags_activity.comment_id,
+ longdescs_tags_activity.bug_when
+ FROM longdescs_tags_activity
+ $tags_activity_joins
+ INNER JOIN profiles
+ ON profiles.userid = longdescs_tags_activity.who
+ WHERE profiles.login_name IN ($who_bits)
+ AND longdescs_tags_activity.bug_when >= ?
+ AND longdescs_tags_activity.bug_when <= ?
+ $tags_activity_where
+
+ UNION ALL
+
+ SELECT
+ 'bug_id' AS name,
+ bugs.bug_id,
+ NULL AS attach_id,
+ ".$dbh->sql_date_format('bugs.creation_ts', '%Y.%m.%d %H:%i:%s')." AS ts,
+ '(new bug)' AS removed,
+ bugs.short_desc AS added,
+ profiles.login_name,
+ NULL AS comment_id,
+ bugs.creation_ts AS bug_when
+ FROM bugs
+ INNER JOIN profiles
+ ON profiles.userid = bugs.reporter
+ WHERE profiles.login_name IN ($who_bits)
+ AND bugs.creation_ts >= ? AND bugs.creation_ts <= ?
+
+ UNION ALL
+
+ SELECT
+ 'longdesc' AS name,
+ longdescs.bug_id,
+ NULL AS attach_id,
+ DATE_FORMAT(longdescs.bug_when, '%Y.%m.%d %H:%i:%s') AS ts,
+ '' AS removed,
+ '' AS added,
+ profiles.login_name,
+ longdescs.comment_id AS comment_id,
+ longdescs.bug_when
+ FROM longdescs
+ INNER JOIN profiles
+ ON profiles.userid = longdescs.who
+ WHERE profiles.login_name IN ($who_bits)
+ AND longdescs.bug_when >= ? AND longdescs.bug_when <= ?
+ $comment_filter
+
+ UNION ALL
+
+ SELECT
+ 'attachments.description' AS name,
+ attachments.bug_id,
+ attachments.attach_id,
+ ".$dbh->sql_date_format('attachments.creation_ts', '%Y.%m.%d %H:%i:%s')." AS ts,
+ '(new attachment)' AS removed,
+ attachments.description AS added,
+ profiles.login_name,
+ NULL AS comment_id,
+ attachments.creation_ts AS bug_when
+ FROM attachments
+ INNER JOIN profiles
+ ON profiles.userid = attachments.submitter_id
+ WHERE profiles.login_name IN ($who_bits)
+ AND attachments.creation_ts >= ? AND attachments.creation_ts <= ?
+ $attachments_where
+
+ ORDER BY $order ";
+
+ my $list = $dbh->selectall_arrayref($query, undef, @params);
+
+ if ($input->{debug}) {
+ while (my $param = shift @params) {
+ $query =~ s/\?/$dbh->quote($param)/e;
+ }
+ $vars->{debug_sql} = $query;
+ }
+
+ my @operations;
+ my $operation = {};
+ my $changes = [];
+ my $incomplete_data = 0;
+ my %bug_ids;
+
+ foreach my $entry (@$list) {
+ my ($fieldname, $bugid, $attachid, $when, $removed, $added, $who,
+ $comment_id) = @$entry;
+ my %change;
+ my $activity_visible = 1;
+
+ next unless Bugzilla->user->can_see_bug($bugid);
+
+ # check if the user should see this field's activity
+ if ($fieldname eq 'remaining_time'
+ || $fieldname eq 'estimated_time'
+ || $fieldname eq 'work_time'
+ || $fieldname eq 'deadline')
+ {
+ $activity_visible = Bugzilla->user->is_timetracker;
+ }
+ elsif ($fieldname eq 'longdescs.isprivate'
+ && !Bugzilla->user->is_insider
+ && $added)
+ {
+ $activity_visible = 0;
+ }
+ else {
+ $activity_visible = 1;
+ }
+
+ if ($activity_visible) {
+ # Check for the results of an old Bugzilla data corruption bug
+ if (($added eq '?' && $removed eq '?')
+ || ($added =~ /^\? / || $removed =~ /^\? /)) {
+ $incomplete_data = 1;
+ }
+
+ # Start a new changeset if required (depends on the grouping type)
+ my $is_new_changeset;
+ if ($order eq 'bug_when') {
+ $is_new_changeset =
+ $operation->{'who'} &&
+ (
+ $who ne $operation->{'who'}
+ || $when ne $operation->{'when'}
+ || $bugid != $operation->{'bug'}
+ );
+ } else {
+ $is_new_changeset =
+ $operation->{'bug'} &&
+ $bugid != $operation->{'bug'};
+ }
+ if ($is_new_changeset) {
+ $operation->{'changes'} = $changes;
+ push (@operations, $operation);
+ $operation = {};
+ $changes = [];
+ }
+
+ $bug_ids{$bugid} = 1;
+
+ $operation->{'bug'} = $bugid;
+ $operation->{'who'} = $who;
+ $operation->{'when'} = $when;
+
+ $change{'fieldname'} = $fieldname;
+ $change{'attachid'} = $attachid;
+ $change{'removed'} = $removed;
+ $change{'added'} = $added;
+ $change{'when'} = $when;
+
+ if ($comment_id) {
+ $change{'comment'} = Bugzilla::Comment->new($comment_id);
+ next if $change{'comment'}->count == 0;
+ }
+
+ if ($attachid) {
+ $change{'attach'} = Bugzilla::Attachment->new($attachid);
+ }
+
+ push (@$changes, \%change);
+ }
+ }
+
+ if ($operation->{'who'}) {
+ $operation->{'changes'} = $changes;
+ push (@operations, $operation);
+ }
+
+ $vars->{'incomplete_data'} = $incomplete_data;
+ $vars->{'operations'} = \@operations;
+
+ my @bug_ids = sort { $a <=> $b } keys %bug_ids;
+ $vars->{'bug_ids'} = \@bug_ids;
+ }
+
+ $vars->{'action'} = $action;
+ $vars->{'who'} = join(',', @who);
+ $vars->{'who_count'} = scalar @who;
+ $vars->{'from'} = $from;
+ $vars->{'to'} = $to;
+ $vars->{'group'} = $input->{'group'};
+}
+
+1;
diff --git a/extensions/BMO/lib/Util.pm b/extensions/BMO/lib/Util.pm
new file mode 100644
index 000000000..df781b9d2
--- /dev/null
+++ b/extensions/BMO/lib/Util.pm
@@ -0,0 +1,90 @@
+# 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.
+
+package Bugzilla::Extension::BMO::Util;
+use strict;
+use warnings;
+
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Date::Parse;
+use DateTime;
+
+use base qw(Exporter);
+
+our @EXPORT = qw( string_to_datetime
+ time_to_datetime
+ parse_date
+ is_active_status_field );
+
+sub string_to_datetime {
+ my $input = shift;
+ my $time = parse_date($input)
+ or ThrowUserError('report_invalid_date', { date => $input });
+ return time_to_datetime($time);
+}
+
+sub time_to_datetime {
+ my $time = shift;
+ return DateTime->from_epoch(epoch => $time)
+ ->set_time_zone('local')
+ ->truncate(to => 'day');
+}
+
+sub parse_date {
+ my ($str) = @_;
+ if ($str =~ /^(-|\+)?(\d+)([hHdDwWmMyY])$/) {
+ # relative date
+ my ($sign, $amount, $unit, $date) = ($1, $2, lc $3, time);
+ my ($sec, $min, $hour, $mday, $month, $year, $wday) = localtime($date);
+ $amount = -$amount if $sign && $sign eq '+';
+ if ($unit eq 'w') {
+ # convert weeks to days
+ $amount = 7 * $amount + $wday;
+ $unit = 'd';
+ }
+ if ($unit eq 'd') {
+ $date -= $sec + 60 * $min + 3600 * $hour + 24 * 3600 * $amount;
+ return $date;
+ }
+ elsif ($unit eq 'y') {
+ return str2time(sprintf("%4d-01-01 00:00:00", $year + 1900 - $amount));
+ }
+ elsif ($unit eq 'm') {
+ $month -= $amount;
+ while ($month < 0) { $year--; $month += 12; }
+ return str2time(sprintf("%4d-%02d-01 00:00:00", $year + 1900, $month + 1));
+ }
+ elsif ($unit eq 'h') {
+ # Special case 0h for 'beginning of this hour'
+ if ($amount == 0) {
+ $date -= $sec + 60 * $min;
+ } else {
+ $date -= 3600 * $amount;
+ }
+ return $date;
+ }
+ return undef;
+ }
+ return str2time($str);
+}
+
+sub is_active_status_field {
+ my ($field) = @_;
+
+ if ($field->type == FIELD_TYPE_EXTENSION
+ && $field->isa('Bugzilla::Extension::TrackingFlags::Flag')
+ && $field->flag_type eq 'tracking'
+ && $field->name =~ /_status_/
+ ) {
+ return $field->is_active;
+ }
+
+ return 0;
+}
+
+1;
diff --git a/extensions/BMO/lib/WebService.pm b/extensions/BMO/lib/WebService.pm
new file mode 100644
index 000000000..ed94aabfc
--- /dev/null
+++ b/extensions/BMO/lib/WebService.pm
@@ -0,0 +1,200 @@
+# -*- 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 BMO Bugzilla Extension.
+#
+# The Initial Developer of the Original Code is Mozilla Foundation. Portions created
+# by the Initial Developer are Copyright (C) 2011 the Mozilla Foundation. All
+# Rights Reserved.
+#
+# Contributor(s):
+# Dave Lawrence <dkl@mozilla.com>
+
+package Bugzilla::Extension::BMO::WebService;
+
+use strict;
+use warnings;
+
+use base qw(Bugzilla::WebService);
+
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Util qw(detaint_natural trick_taint);
+use Bugzilla::WebService::Util qw(validate);
+use Bugzilla::Field;
+
+sub getBugsConfirmer {
+ my ($self, $params) = validate(@_, 'names');
+ my $dbh = Bugzilla->dbh;
+
+ defined($params->{names})
+ || ThrowCodeError('params_required',
+ { function => 'BMO.getBugsConfirmer', params => ['names'] });
+
+ my @user_objects = map { Bugzilla::User->check($_) } @{ $params->{names} };
+
+ # start filtering to remove duplicate user ids
+ @user_objects = values %{{ map { $_->id => $_ } @user_objects }};
+
+ my $fieldid = get_field_id('bug_status');
+
+ my $query = "SELECT DISTINCT bugs_activity.bug_id
+ FROM bugs_activity
+ LEFT JOIN bug_group_map
+ ON bugs_activity.bug_id = bug_group_map.bug_id
+ WHERE bugs_activity.fieldid = ?
+ AND bugs_activity.added = 'NEW'
+ AND bugs_activity.removed = 'UNCONFIRMED'
+ AND bugs_activity.who = ?
+ AND bug_group_map.bug_id IS NULL
+ ORDER BY bugs_activity.bug_id";
+
+ my %users;
+ foreach my $user (@user_objects) {
+ my $bugs = $dbh->selectcol_arrayref($query, undef, $fieldid, $user->id);
+ $users{$user->login} = $bugs;
+ }
+
+ return \%users;
+}
+
+sub getBugsVerifier {
+ my ($self, $params) = validate(@_, 'names');
+ my $dbh = Bugzilla->dbh;
+
+ defined($params->{names})
+ || ThrowCodeError('params_required',
+ { function => 'BMO.getBugsVerifier', params => ['names'] });
+
+ my @user_objects = map { Bugzilla::User->check($_) } @{ $params->{names} };
+
+ # start filtering to remove duplicate user ids
+ @user_objects = values %{{ map { $_->id => $_ } @user_objects }};
+
+ my $fieldid = get_field_id('bug_status');
+
+ my $query = "SELECT DISTINCT bugs_activity.bug_id
+ FROM bugs_activity
+ LEFT JOIN bug_group_map
+ ON bugs_activity.bug_id = bug_group_map.bug_id
+ WHERE bugs_activity.fieldid = ?
+ AND bugs_activity.removed = 'RESOLVED'
+ AND bugs_activity.added = 'VERIFIED'
+ AND bugs_activity.who = ?
+ AND bug_group_map.bug_id IS NULL
+ ORDER BY bugs_activity.bug_id";
+
+ my %users;
+ foreach my $user (@user_objects) {
+ my $bugs = $dbh->selectcol_arrayref($query, undef, $fieldid, $user->id);
+ $users{$user->login} = $bugs;
+ }
+
+ return \%users;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Extension::BMO::Webservice - The BMO WebServices API
+
+=head1 DESCRIPTION
+
+This module contains API methods that are useful to user's of bugzilla.mozilla.org.
+
+=head1 METHODS
+
+See L<Bugzilla::WebService> for a description of how parameters are passed,
+and what B<STABLE>, B<UNSTABLE>, and B<EXPERIMENTAL> mean.
+
+=head2 getBugsConfirmer
+
+B<UNSTABLE>
+
+=over
+
+=item B<Description>
+
+This method returns public bug ids that a given user has confirmed (changed from
+C<UNCONFIRMED> to C<NEW>).
+
+=item B<Params>
+
+You pass a field called C<names> that is a list of Bugzilla login names to find bugs for.
+
+=over
+
+=item C<names> (array) - An array of strings representing Bugzilla login names.
+
+=back
+
+=item B<Returns>
+
+=over
+
+A hash of Bugzilla login names. Each name points to an array of bug ids that the user has confirmed.
+
+=back
+
+=item B<Errors>
+
+=item B<History>
+
+=over
+
+=item Added in BMO Bugzilla B<4.0>.
+
+=back
+
+=back
+
+=head2 getBugsVerifier
+
+B<UNSTABLE>
+
+=over
+
+=item B<Description>
+
+This method returns public bug ids that a given user has verified (changed from
+C<RESOLVED> to C<VERIFIED>).
+
+=item B<Params>
+
+You pass a field called C<names> that is a list of Bugzilla login names to find bugs for.
+
+=over
+
+=item C<names> (array) - An array of strings representing Bugzilla login names.
+
+=back
+
+=item B<Returns>
+
+=over
+
+A hash of Bugzilla login names. Each name points to an array of bug ids that the user has verified.
+
+=back
+
+=item B<Errors>
+
+=item B<History>
+
+=over
+
+=item Added in BMO Bugzilla B<4.0>.
+
+=back
+
+=back
diff --git a/extensions/BMO/t/bug_format_comment.t b/extensions/BMO/t/bug_format_comment.t
new file mode 100644
index 000000000..0356684e9
--- /dev/null
+++ b/extensions/BMO/t/bug_format_comment.t
@@ -0,0 +1,84 @@
+#!/usr/bin/perl -T
+# 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.
+use strict;
+use warnings;
+use lib qw( . lib );
+
+use Test::More;
+use Bugzilla;
+use Bugzilla::Extension;
+
+my $class = Bugzilla::Extension->load('extensions/BMO/Extension.pm',
+ 'extensions/BMO/Config.pm');
+ok( $class->can('bug_format_comment'), 'the function exists');
+
+my $bmo = $class->new;
+ok($bmo, "got a new bmo extension");
+
+my $text = <<'END_OF_LINKS';
+# crash stats, a fake one
+bp-deadbeef-deaf-beef-beed-cafefeed1337
+
+# CVE/CAN security things
+CVE-2014-0160
+
+# svn
+r2424
+
+# bzr commit
+Committing to: bzr+ssh://dlawrence%40mozilla.com@bzr.mozilla.org/bmo/4.2
+modified extensions/Review/Extension.pm
+Committed revision 9257.
+
+# git with scp-style address
+To gitolite3@git.mozilla.org:bugzilla/bugzilla.git
+ 36f56bd..eab44b1 nouri -> nouri
+
+# git with uri (with login)
+To ssh://gitolite3@git.mozilla.org/bugzilla/bugzilla.git
+ 36f56bd..eab44b1 withuri -> withuri
+
+# git with uri (without login)
+To ssh://git.mozilla.org/bugzilla/bugzilla.git
+ 36f56bd..eab44b1 nologin -> nologin
+END_OF_LINKS
+
+my @regexes;
+
+$bmo->bug_format_comment({ regexes => \@regexes });
+
+ok(@regexes > 0, "got some regexes to play with");
+
+foreach my $re (@regexes) {
+ my ($match, $replace) = @$re{qw(match replace)};
+ if (ref($replace) eq 'CODE') {
+ $text =~ s/$match/$replace->({matches => [ $1, $2, $3, $4,
+ $5, $6, $7, $8,
+ $9, $10]})/egx;
+ }
+ else {
+ $text =~ s/$match/$replace/egx;
+ }
+}
+
+my @links = (
+ '<a href="https://crash-stats.mozilla.com/report/index/deadbeef-deaf-beef-beed-cafefeed1337">bp-deadbeef-deaf-beef-beed-cafefeed1337</a>',
+ '<a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0160">CVE-2014-0160</a>',
+ '<a href="http://viewvc.svn.mozilla.org/vc?view=rev&amp;revision=2424">r2424</a>',
+ '<a href="http://git.mozilla.org/?p=bugzilla/bugzilla.git;a=commit;h=eab44b1">36f56bd..eab44b1 withuri -> withuri</a>',
+ '<a href="http://git.mozilla.org/?p=bugzilla/bugzilla.git;a=commit;h=eab44b1">36f56bd..eab44b1 nouri -> nouri</a>',
+ '<a href="http://git.mozilla.org/?p=bugzilla/bugzilla.git;a=commit;h=eab44b1">36f56bd..eab44b1 nologin -> nologin</a>',
+ 'http://bzr.mozilla.org/bmo/4.2/revision/9257',
+);
+
+foreach my $link (@links) {
+ ok(index($text, $link) > -1, "check for $link");
+}
+
+
+done_testing;
diff --git a/extensions/BMO/template/en/default/account/create.html.tmpl b/extensions/BMO/template/en/default/account/create.html.tmpl
new file mode 100644
index 000000000..38acb6320
--- /dev/null
+++ b/extensions/BMO/template/en/default/account/create.html.tmpl
@@ -0,0 +1,178 @@
+[%# 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 <gerv@gerv.net>
+ # Byron Jones <glob@mozilla.com>
+ #%]
+
+[%# INTERFACE
+ # none
+ #
+ # Param("maintainer") is used to display the maintainer's email.
+ # Param("emailsuffix") is used to pre-fill the email field.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% title = BLOCK %]
+ Create a new [% terms.Bugzilla %] account
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = title
+ style_urls = [ 'extensions/BMO/web/styles/create_account.css' ]
+%]
+
+<script type="text/javascript">
+function onSubmit() {
+ var email = document.getElementById('login').value;
+ if (email == '') {
+ alert('You must enter your email address.');
+ return false;
+ }
+ var isValid =
+ email.match(/@/)
+ && email.match(/@.+\./)
+ && !email.match(/\.$/)
+ && !email.match(/[\\()&<>,'"\[\]]/)
+ ;
+ if (!isValid) {
+ alert(
+ "The e-mail address doesn't pass our syntax checking for a legal " +
+ "email address.\n\nA legal address must contain exactly one '@', and " +
+ "at least one '.' after the @.\n\nIt must also not contain any of " +
+ "these special characters: \ ( ) & < > , ; : \" [ ], or any whitespace."
+ );
+ return false;
+ }
+ return true;
+}
+</script>
+
+<table border="0" id="create-account">
+<tr>
+
+<td width="50%" id="create-account-left" valign="top">
+
+ <h2 class="column-header">I need help using a Mozilla Product</h2>
+
+ <table border="0" id="product-list">
+ [% INCLUDE product
+ icon = "firefox"
+ name = "Firefox Support"
+ url = "http://support.mozilla.com/"
+ desc = "Support for the Firefox web browser."
+ %]
+ [% INCLUDE product
+ icon = "firefox"
+ name = "Firefox for Mobile Support"
+ url = "http://support.mozilla.com/mobile"
+ desc = "Support for the Firefox Mobile web browser."
+ %]
+ [% INCLUDE product
+ icon = "thunderbird"
+ name = "Thunderbird Support"
+ url = "http://www.mozillamessaging.com/support/"
+ desc = "Support for Thunderbird email client."
+ %]
+ [% INCLUDE product
+ icon = "other"
+ name = "Support for other products"
+ url = "http://www.mozilla.org/projects/"
+ desc = "Support for products not listed here."
+ %]
+ [% INCLUDE product
+ icon = "input"
+ name = "Feedback"
+ url = "http://input.mozilla.com/feedback"
+ desc = "Report issues with a web site that you use, or provide quick feedback for Firefox."
+ %]
+ </table>
+
+</td>
+
+<td width="50%" id="create-account-right" valign="top">
+
+ <h2 class="column-header">I want to help</h2>
+
+ <div id="right-blurb">
+ <p>
+ Great! There are three things to know and do:
+ </p>
+ <ol>
+ <li>
+ Please consider reading our
+ <a href="https://developer.mozilla.org/en/Bug_writing_guidelines" target="_blank">[% terms.bug %] writing guidelines</a>.
+ </li>
+ <li>
+ [% terms.Bugzilla %] is a public place, so what you type and your email address will be visible
+ to all logged-in users. Some people use an
+ <a href="http://email.about.com/od/freeemailreviews/tp/free_email.htm" target="_blank">alternative email address</a>
+ for this reason.
+ </li>
+ <li>
+ Please give us an email address you want to use. Once we confirm that it works,
+ you'll be asked to set a password and then you can start filing [% terms.bugs %] and helping fix them.
+ </li>
+ </ol>
+ </div>
+
+ <h2 class="column-header">Create an account</h2>
+
+ <form method="post" action="createaccount.cgi" onsubmit="return onSubmit()">
+ <table id="create-account-form">
+ <tr>
+ <td class="label">Email Address:</td>
+ <td>
+ <input size="35" id="login" name="login" placeholder="you@example.com">[% Param('emailsuffix') FILTER html %]</td>
+ <td>
+ <input type="hidden" id="token" name="token" value="[% issue_hash_token(['create_account']) FILTER html %]">
+ <input type="submit" value="Create Account">
+ </td>
+ </tr>
+ </table>
+ </form>
+
+ [% Hook.process('additional_methods') %]
+
+</td>
+
+</tr>
+</table>
+
+<p id="bmo-admin">
+ If you think there's something wrong with [% terms.Bugzilla %], you can
+ <a href="mailto:bugzilla-admin@mozilla.org">send an email to the admins</a>, but
+ remember, they can't file [% terms.bugs %] for you, or solve tech support problems.
+</p>
+
+[% PROCESS global/footer.html.tmpl %]
+
+[% BLOCK product %]
+ <tr>
+ <td valign="top">
+ <a href="[% url FILTER none %]"><img
+ src="extensions/BMO/web/producticons/[% icon FILTER uri %].png"
+ border="0" width="64" height="64"></a>
+ </td>
+ <td valign="top">
+ <h2><a href="[% url FILTER none %]">[% name FILTER html %]</a></h2>
+ <div>[% desc FILTER html %]</div>
+ </td>
+ </tr>
+[% END %]
+
diff --git a/extensions/BMO/template/en/default/bug/create/comment-automative.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-automative.txt.tmpl
new file mode 100644
index 000000000..c23a6427d
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-automative.txt.tmpl
@@ -0,0 +1,52 @@
+[%# 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.
+ #%]
+[% PROCESS global/variables.none.tmpl %]
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi +%]
+>>Problem:
+[%+ cgi.param('desc_problem') %]
+
+>>Solution:
+[%+ cgi.param('desc_solution') %]
+
+>>Mozilla Top Level Goal:
+[%+ cgi.param('desc_top_level_goal') %]
+
+>>Existing [% terms.Bug %]:
+[% IF cgi.param('existing_bug') %]
+[%+ terms.Bug %] [% cgi.param("existing_bug") %]
+[% ELSE %]
+No [% terms.bug %]
+[% END %]
+
+>>Per-Commit:
+[%+ cgi.param('per_commit') || 'No' %]
+
+>>Data other than Pass/Fail:
+[%+ cgi.param('desc_data_produce') || 'No' %]
+
+>>Prototype Date:
+[%+ cgi.param("prototype_date") || 'Not provided' %]
+
+>>Production Date:
+[%+ cgi.param("production_date") || 'Not provided' %]
+
+>>Most Valuable Piece:
+[%+ cgi.param('most_valuable_piece') || 'Not provided' %]
+
+>>Responsible Engineer:
+[%+ cgi.param('responsible_engineer') || 'Not provided' %]
+
+>>Manager:
+[%+ cgi.param('manager') || 'Not provided' %]
+
+>>Other Teams/External Dependencies:
+[%+ cgi.param('other_teams') || 'Not provided' %]
+
+>>Additional Info:
+[%+ cgi.param('additional_info') || 'Not provided' %]
diff --git a/extensions/BMO/template/en/default/bug/create/comment-creative.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-creative.txt.tmpl
new file mode 100644
index 000000000..311736b5e
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-creative.txt.tmpl
@@ -0,0 +1,39 @@
+[%# 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.
+ #%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi +%]
+>>Project/Request Title:
+[%+ cgi.param('short_desc') %]
+
+>>Project Overview:
+[%+ cgi.param('overview') %]
+
+>> Creative Help Needed:
+Copy: [% IF cgi.param('type_copy') %] Yes [% ELSE %] No [% END %]
+Design: [% IF cgi.param('type_design') %] Yes [% ELSE %] No [% END %]
+Video: [% IF cgi.param('type_video') %] Yes [% ELSE %] No [% END %]
+Other: [% IF cgi.param('type_other') %][% cgi.param('type_other_text') %][% ELSE %]No[% END %]
+
+>>Creative Specs:
+[%+ cgi.param("specs") %]
+
+>>CTA and Design:
+[%+ cgi.param('cta_design') %]
+
+>>Creative Due Date:
+[%+ cgi.param("cf_due_date") || 'Not provided' %]
+
+>>Launch Date:
+[%+ cgi.param("launch_date") || 'Not provided' %]
+
+>>Mozilla Goal:
+[%+ IF cgi.param("goal_other") %][% cgi.param("goal_other") %][% ELSE %][% cgi.param("goal") %][% END %]
+
+>>Points of Contact:
+[%+ cgi.param('cc').join(', ') || 'Not provided' %]
diff --git a/extensions/BMO/template/en/default/bug/create/comment-dev-engagement-event.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-dev-engagement-event.txt.tmpl
new file mode 100644
index 000000000..cb7473e22
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-dev-engagement-event.txt.tmpl
@@ -0,0 +1,84 @@
+[%# 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.
+ #%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+
+::
+
+Name:
+[%+ cgi.param('name') %]
+
+Email Address:
+[%+ cgi.param('email') %]
+
+Role in relation to event:
+[%+ cgi.param('role') %]
+
+::
+
+Event Name:
+[%+ cgi.param('event') %]
+
+Start Date:
+[%+ cgi.param('start_date') %]
+
+End Date:
+[%+ cgi.param('end_date') %]
+
+Event Location:
+[%+ cgi.param('location') || "-" %]
+
+Venue:
+[%+ cgi.param('venue') || "-" %]
+
+Weblink:
+[%+ cgi.param('link') || "-" %]
+
+Expected Attendees:
+[%+ cgi.param('attendees') || "-" %]
+
+Event Description:
+[%+ cgi.param('desc') || "-" %]
+
+Primary Audience:
+[%+ cgi.param('audience') || "-" %]
+
+Relevant Products:
+[% "\n* Firefox OS" IF cgi.param('product-fxos') %]
+[% "\n* Firefox Web Browser" IF cgi.param('product-fx') %]
+[% "\n* Webmaker" IF cgi.param('product-webmaker') %]
+[% "\n* Persona" IF cgi.param('product-persona') %]
+[% "\n* Marketplace" IF cgi.param('product-marketplace') %]
+[% "\n* Thunderbird" IF cgi.param('product-tb') %]
+[% "\n* The Free and Open Web" IF cgi.param('product-fow') %]
+[% "\n* Other: " _ cgi.param('product-other-text') IF cgi.param('product-other') %]
+
+::
+
+Requests:
+[% "\n* Keynote Presentation" IF cgi.param('request-keynote') %]
+[% "\n* Talk Presentation" IF cgi.param('request-talk') %]
+[% "\n* Workshop" IF cgi.param('request-workshop') %]
+[% "\n* Sponsorship" IF cgi.param('request-sponsorship') %]
+[% "\n* Other: " _ cgi.param('request-other-text') IF cgi.param('request-other') %]
+
+Suggested sponsorship amount/level:
+[%+ cgi.param('sponsorship-suggestion') || "-" %]
+
+Already Registered Mozillians:
+[%+ cgi.param('mozillians') || "-" %]
+
+Requesting A Specific Person:
+[%+ cgi.param('specific') || "-" %]
+
+Alternative Person:
+[%+ cgi.param('fallback') || "-" %]
+
+Anything Else:
+[%+ cgi.param('else') || "-" %]
diff --git a/extensions/BMO/template/en/default/bug/create/comment-doc.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-doc.txt.tmpl
new file mode 100644
index 000000000..4c878a867
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-doc.txt.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.
+ #%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi +%]
+:: Developer Documentation Request
+
+ Request Type: [% cgi.param("type") %]
+ Gecko Version: [% cgi.param("gecko") %]
+ Technical Contact: [% cgi.param("cc") %]
+
+:: Details
+
+[%+ cgi.param("details") %]
+
diff --git a/extensions/BMO/template/en/default/bug/create/comment-employee-incident.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-employee-incident.txt.tmpl
new file mode 100644
index 000000000..1b0902d64
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-employee-incident.txt.tmpl
@@ -0,0 +1,57 @@
+[%# 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 BMO Bugzilla 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):
+ # David Lawrence <dkl@mozilla.com>
+ #%]
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+
+[% IF cgi.param('incident_type') == 'stolen' %]
+[% IF original_reporter -%]
+Reporter: [% original_reporter.identity FILTER none %]
+[%- END -%]
+
+ [% IF cgi.param('display_action') %]
+ [% IF cgi.param('display_action') == 'ldap' %]
+Action needed: Please immediately reset the LDAP password for this user.
+ [% ELSIF cgi.param('display_action') == 'ssh' %]
+Action needed: Please immediately disable the SSH key for this user.
+ [% END %]
+
+The user reported that their mobile or laptop device has been lost or stolen.
+This ticket was automatically generated from the employee incident reporting
+form. An additional ticket has been filed (see blocker bugs) for InfraSec to
+review the impact of this lost device.
+ [% END %]
+
+Type of device: [% cgi.param('device') %]
+Was the device encrypted?: [% cgi.param('encrypted') %]
+Any user data on the device?: [% cgi.param('userdata') %]
+ [% IF cgi.param('userdata') == 'Yes' %]
+Sensitive data on the device:
+[%+ cgi.param('sensitivedata') %]
+ [% END %]
+Browser configured to remember passwords?: [% cgi.param('rememberpasswords') %]
+ [% IF cgi.param('rememberpasswords') == 'Yes' %]
+Critical sites:
+[%+ cgi.param('criticalsites') %]
+ [% END %]
+[% END %]
+[% IF cgi.param('comment') %]
+Extra Notes:
+[%+ cgi.param('comment') %]
+[% END %]
diff --git a/extensions/BMO/template/en/default/bug/create/comment-finance.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-finance.txt.tmpl
new file mode 100644
index 000000000..f0427b4c5
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-finance.txt.tmpl
@@ -0,0 +1,35 @@
+[%# 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.
+ #%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+
+Request Type: [% cgi.param('component') %]
+Summary: [% cgi.param('short_desc') %]
+Priority to your Team: [% cgi.param('team_priority') %]
+Timeframe for Signature: [% cgi.param('signature_time') %]
+
+Name of Other Party:
+[%+ cgi.param('other_party') %]
+
+Business Objective:
+[%+ cgi.param('business_obj') %]
+
+What is this purchase?:
+[%+ cgi.param('what_purchase') %]
+
+Why is this purchase needed?:
+[%+ cgi.param('why_purchase') %]
+
+What is the risk if this is not purchased?:
+[%+ cgi.param('risk_purchase') %]
+
+What is the alternative?:
+[%+ cgi.param('alternative_purchase') %]
+
+Total Cost: [% cgi.param('total_cost') %]
diff --git a/extensions/BMO/template/en/default/bug/create/comment-fxos-betaprogram.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-fxos-betaprogram.txt.tmpl
new file mode 100644
index 000000000..9370ff03c
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-fxos-betaprogram.txt.tmpl
@@ -0,0 +1,24 @@
+[%# 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.
+ #%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+
+Phone:
+[%+ cgi.param('phone') == 'Other' ? cgi.param('phone_other') : cgi.param('phone') %]
+
+Firefox OS Version:
+[%+ cgi.param('fxos_version') %]
+
+Issue Details:
+[%+ cgi.param('details') %]
+
+[% IF cgi.param('app') %]
+Associated App:
+[%+ cgi.param('app') %]
+[% END %]
diff --git a/extensions/BMO/template/en/default/bug/create/comment-fxos-feature.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-fxos-feature.txt.tmpl
new file mode 100644
index 000000000..65224bfba
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-fxos-feature.txt.tmpl
@@ -0,0 +1,24 @@
+[%# 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.
+ #%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi +%]
+>> Feature Request Title:
+[%+ cgi.param('short_desc') %]
+
+>> Description of feature, or problem to be solved
+[%+ cgi.param("description") %]
+
+>> Impact of implementing the feature/solution
+[%+ cgi.param("implement_impact") %]
+
+>> Impact of NOT implementing the feature/solution
+[%+ cgi.param("not_implement_impact") %]
+
+>> Date required
+[%+ cgi.param("date_required") %]
diff --git a/extensions/BMO/template/en/default/bug/create/comment-fxos-mcts-waiver.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-fxos-mcts-waiver.txt.tmpl
new file mode 100644
index 000000000..abad3f3c4
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-fxos-mcts-waiver.txt.tmpl
@@ -0,0 +1,36 @@
+[%# 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.
+ #%]
+[% PROCESS global/variables.none.tmpl %]
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi +%]
+> Company Name
+[%+ cgi.param('company_name') %]
+
+> Device Description
+[%+ cgi.param('device_desc') %]
+
+> Firefox OS Release
+[%+ cgi.param('ffos_release') %]
+
+> Branding Tier
+[%+ cgi.param('branding_tier') %]
+
+> Distribution Countries
+[%+ cgi.param('dist_countries') %]
+
+> Distribution Channel
+[%+ cgi.param('dist_channel') %]
+
+> Reason for Waiver Request
+[%+ cgi.param('reason') %]
+
+> Rationale for Granting Waiver Request
+[%+ cgi.param('rationale') %]
+
+> Impact Analysis
+[%+ cgi.param('impact') %]
diff --git a/extensions/BMO/template/en/default/bug/create/comment-fxos-partner.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-fxos-partner.txt.tmpl
new file mode 100644
index 000000000..aa26d778f
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-fxos-partner.txt.tmpl
@@ -0,0 +1,23 @@
+[%# 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.
+ #%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+
+What are the steps to reproduce?:
+[%+ cgi.param('steps_to_reproduce') %]
+
+What was the actual behavior?:
+[%+ cgi.param('actual_behavior') %]
+
+What was the expected behavior?:
+[%+ cgi.param('expected_behavior') %]
+
+What build were you using?: [% cgi.param('build') %]
+
+What are the requirements?: [% cgi.param('requirements') %]
diff --git a/extensions/BMO/template/en/default/bug/create/comment-fxos-preload-app.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-fxos-preload-app.txt.tmpl
new file mode 100644
index 000000000..a4e489724
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-fxos-preload-app.txt.tmpl
@@ -0,0 +1,28 @@
+[%# 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.
+ #%]
+[% PROCESS global/variables.none.tmpl %]
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi +%]
+
+>>Company Name
+[%+ cgi.param('company_name') %]
+
+>>Apps Business Development Contact
+[%+ cgi.param('apps_business_dev_contact') %]
+
+>>Name of Firefox Marketplace apps of interest to you:
+[%+ cgi.param('preload_apps') %]
+
+>>Countries where your device will be distributed
+[%+ cgi.param('countries') %]
+
+>>Release Information
+[%+ cgi.param('release_info') %]
+
+>>Device Information
+[%+ cgi.param('device_info') %]
diff --git a/extensions/BMO/template/en/default/bug/create/comment-ipp.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-ipp.txt.tmpl
new file mode 100644
index 000000000..5c73587a9
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-ipp.txt.tmpl
@@ -0,0 +1,30 @@
+[%# 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.
+ #%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi +%]
+:: Internet Public Policy Issue
+
+Region/Country: [% cgi.param("region") %]
+
+:: Description
+
+[%+ cgi.param("desc") %]
+
+:: Relevance
+
+[%+ cgi.param("relevance") %]
+
+Goal: [% cgi.param("goal") %]
+When: [% cgi.param("when") %]
+
+[% IF cgi.param("additional") %]
+:: Additional Information
+
+[%+ cgi.param("additional") %]
+[% END %]
diff --git a/extensions/BMO/template/en/default/bug/create/comment-legal.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-legal.txt.tmpl
new file mode 100644
index 000000000..eb00a88d9
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-legal.txt.tmpl
@@ -0,0 +1,39 @@
+[%# 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 BMO Bugzilla 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):
+ # David Lawrence <dkl@mozilla.com>
+ #%]
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+
+Priority for your Team:
+[%+ cgi.param('teampriority') %]
+
+Timeframe for Completion:
+[%+ cgi.param('timeframe') %]
+
+Goal:
+[%+ cgi.param('goal') %]
+
+Business Objective:
+[%+ cgi.param('busobj') %]
+
+Other Party:
+[%+ cgi.param('otherparty') %]
+
+Description:
+[%+ cgi.param("comment") %]
diff --git a/extensions/BMO/template/en/default/bug/create/comment-mdn.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-mdn.txt.tmpl
new file mode 100644
index 000000000..60a443d2b
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-mdn.txt.tmpl
@@ -0,0 +1,66 @@
+[%# 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.
+ #%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi +%]
+
+[% IF cgi.param('request_type') == 'Bug' %]
+What did you do?
+================
+[%+ cgi.param('bug_actions') %]
+
+What happened?
+==============
+[%+ cgi.param('bug_actual_results') %]
+
+What should have happened?
+==========================
+[%+ cgi.param('bug_expected_results') %]
+
+[% ELSIF cgi.param('request_type') == 'Feature' %]
+What problems would this solve?
+===============================
+[%+ cgi.param('feature_problem_solving') %]
+
+Who would use this?
+===================
+[%+ cgi.param('feature_audience') %]
+
+What would users see?
+=====================
+[%+ cgi.param('feature_interface') %]
+
+What would users do? What would happen as a result?
+===================================================
+[%+ cgi.param('feature_process') %]
+
+[% ELSIF cgi.param('request_type') == 'Change' %]
+What feature should be changed? Please provide the URL of the feature if possible.
+==================================================================================
+[%+ cgi.param('change_feature') %]
+
+What problems would this solve?
+===============================
+[%+ cgi.param('change_problem_solving') %]
+
+Who would use this?
+===================
+[%+ cgi.param('change_audience') %]
+
+What would users see?
+=====================
+[%+ cgi.param('change_interface') %]
+
+What would users do? What would happen as a result?
+===================================================
+[%+ cgi.param('change_process') %]
+
+[% END %]
+Is there anything else we should know?
+======================================
+[%+ cgi.param("description") %]
diff --git a/extensions/BMO/template/en/default/bug/create/comment-mobile-compat.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-mobile-compat.txt.tmpl
new file mode 100644
index 000000000..37b7d98d5
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-mobile-compat.txt.tmpl
@@ -0,0 +1,33 @@
+[%# 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.
+ #%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi +%]
+
+Site: [%+ cgi.param("bug_file_loc") %]
+[%+ cgi.param("short_desc") %]
+
+:: Steps To Reproduce
+
+[%+ cgi.param("desc") %]
+
+:: Expected Result
+
+[%+ cgi.param("expected_result") %]
+
+:: Actual Result
+
+[%+ cgi.param("actual_result") %]
+
+:: Additional Information
+
+Software Version: [% cgi.param("software_version") %]
+[% IF cgi.param("device") %]
+Device Information: [% cgi.param("device") %]
+[% END %]
+Reporter's User Agent: [% cgi.param("user_agent") %]
diff --git a/extensions/BMO/template/en/default/bug/create/comment-mozlist.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-mozlist.txt.tmpl
new file mode 100644
index 000000000..c62461d42
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-mozlist.txt.tmpl
@@ -0,0 +1,44 @@
+[%# 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 <gerv@gerv.net>
+ #%]
+[%# INTERFACE:
+ # This template has no interface.
+ #
+ # Form variables from a bug submission (i.e. the fields on a template from
+ # enter_bug.cgi) can be access via Bugzilla.cgi.param. It can be used to
+ # pull out various custom fields and format an initial Description entry
+ # from them.
+ #%]
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+List Name: [% cgi.param("listName") %]
+List Admin: [% cgi.param("listAdmin") %]
+
+Short Description:
+[%+ cgi.param("listShortDesc") %]
+
+[% IF cgi.param("listType") != "mozilla.com" %]
+Long Description:
+[%+ cgi.param("listLongDesc") %]
+[% END %]
+
+Justification / Special Instructions:
+
+[%+ cgi.param("comment") IF cgi.param("comment") %]
+
diff --git a/extensions/BMO/template/en/default/bug/create/comment-mozpr.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-mozpr.txt.tmpl
new file mode 100644
index 000000000..bfd421388
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-mozpr.txt.tmpl
@@ -0,0 +1,130 @@
+[%# 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.
+ #%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi +%]
+[% PROCESS global/variables.none.tmpl +%]
+
+ Project Title: [% cgi.param("short_desc") %]
+
+Project Description and Scope:
+[%+ cgi.param("desc") %]
+
+== Timings
+
+ Start Date: [% cgi.param("start_date") %]
+ Announcement Date: [% cgi.param("announce_date") %]
+ Internal Deadline: [% cgi.param("deadline") %]
+
+== Owners
+
+ Project PR Owner: [% cgi.param("pr_owner") %]
+[%~ " " _ cgi.param("pr_owner_other") IF cgi.param("pr_owner") == "Other:" %]
+ Project Owner: [% cgi.param("owner") %]
+
+== RASCI
+
+ Responsible: [% cgi.param("rasci_r") || "-" %]
+ Approver: [% cgi.param("rasci_a") %]
+ Supporter: [% cgi.param("rasci_s") || "-" %]
+ Consultant: [% cgi.param("rasci_c") || "-" %]
+ Informed: [% cgi.param("rasci_i") || "-" %]
+
+== Details
+
+ Tier: [% cgi.param("tier") %]
+ PR Approach: [% cgi.param("pr_approach") %]
+Product Group Focus: [% cgi.param("group_focus") %]
+[%~ " " _ cgi.param("group_focus_other") IF cgi.param("group_focus") == "Other:" %]
+ Region: [% cgi.param("region") %]
+[%~ " " _ cgi.param("region_other") IF cgi.param("region") == "Other:" %]
+
+== Goals, Audience, and Messages
+
+Project Goals:
+[%+ cgi.param("project_goals") %]
+
+PR Goals:
+[%+ cgi.param("pr_goals") %]
+
+Company Goal: [% cgi.param("company_goal") %]
+
+Audiences:
+[% FOREACH audience = cgi.param("audience") %]
+ - [% audience %]
+[% " " _ cgi.param("audience_other") IF audience == "Other:" %]
+[% END %]
+
+Key Messages:
+[%+ cgi.param("key_messages") %]
+[% IF cgi.param("proj_mat_online") %]
+
+== Project Materials - Online Documentation
+
+ Description: [% cgi.param("proj_mat_online_desc") %]
+ Link: [% cgi.param("proj_mat_online_link") %]
+[% END %]
+[% IF cgi.param("proj_mat_file") %]
+
+== Project Materials - Attached
+
+ Description: [% cgi.param("proj_mat_file_desc") %]
+ File Name: [% cgi.param("proj_mat_file_attach") %]
+[% END %]
+[% IF cgi.param("pr_mat_online") %]
+
+== PR Project Materials - Online Documentation
+
+ Description: [% cgi.param("pr_mat_online_desc") %]
+ Link: [% cgi.param("pr_mat_online_link") %]
+[% END %]
+[% IF cgi.param("pr_mat_file") %]
+
+== PR Project Materials - Attached
+
+ Description: [% cgi.param("pr_mat_file_desc") %]
+ File Name: [% cgi.param("pr_mat_file_attach") %]
+[% END %]
+
+== Requirements
+
+ Metrica Coverage: [% cgi.param("metrica") %]
+[% IF cgi.param("press_center") %]
+
+Press Center Update:
+[% FOREACH option = cgi.param("press_center") %]
+ - [% option %]
+[% " " _ cgi.param("press_center_other") IF option == "Other:" %]
+[% END %]
+[% END %]
+[% IF cgi.param("resources") || cgi.param("internal_resources") %]
+
+ Internal Resources:
+[% " " _ cgi.param("resources") IF cgi.param("resources") %]
+[% FOREACH option = cgi.param("internal_resources") %]
+ - [% option %]
+[% " " _ cgi.param("internal_resources_other") IF option == "Other:" %]
+[% END %]
+[% END %]
+[% IF cgi.param("resources") || cgi.param("external_resources") %]
+
+ External Resources:
+[% FOREACH option = cgi.param("external_resources") %]
+ - [% option %]
+[% " " _ cgi.param("external_resources_other") IF option == "Other:" %]
+[% END %]
+[% END %]
+
+ Localization: [% cgi.param("localization") %]
+[%~ " " _ cgi.param("localization_other") IF cgi.param("localization") == "Other:" %]
+
+== Budget
+
+ Budget: [% cgi.param("budget") %]
+[%~ " " _ cgi.param("budget_extra") IF cgi.param("budget") == "Extra" %]
+
diff --git a/extensions/BMO/template/en/default/bug/create/comment-privacy-data.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-privacy-data.txt.tmpl
new file mode 100644
index 000000000..279d59b6b
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-privacy-data.txt.tmpl
@@ -0,0 +1,30 @@
+[%# 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.
+ #%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+
+Where does this data come from:
+
+[%+ cgi.param('source') %]
+
+What people and things does this data describe, and what fields does it contain:
+
+[%+ cgi.param('data_desc') %]
+
+What parts of this data do you want to release:
+
+[%+ cgi.param('release') %]
+
+Why are we releasing this data, and what do we hope people will do with it:
+
+[%+ cgi.param('why') %]
+
+Is there a particular time by which you would like to release this data:
+
+[%+ cgi.param('when') %]
diff --git a/extensions/BMO/template/en/default/bug/create/comment-recoverykey.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-recoverykey.txt.tmpl
new file mode 100644
index 000000000..9a38af7cc
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-recoverykey.txt.tmpl
@@ -0,0 +1,28 @@
+[%# 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 BMO Bugzilla 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):
+ # David Lawrence <dkl@mozilla.com>
+ #%]
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+
+Recovery Key: [% cgi.param('recoverykey') %]
+Asset Tag Number: [% cgi.param('assettag') %]
+
+[% IF cgi.param('comment') %]
+[%+ cgi.param('comment') %]
+[% END %]
diff --git a/extensions/BMO/template/en/default/bug/create/comment-swag.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-swag.txt.tmpl
new file mode 100644
index 000000000..920d392da
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-swag.txt.tmpl
@@ -0,0 +1,50 @@
+[%# 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.
+ #%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi +%]
+[% PROCESS global/variables.none.tmpl +%]
+:: Gear Requested
+
+ Purpose of Gear: [% cgi.param("purpose") %] [%+ cgi.param("purpose_other") %]
+ Date Required: [% cgi.param("date_required") || "-" %]
+
+[%+ cgi.param("items") %]
+
+:: Requester
+
+ Name: [% cgi.param('firstname') %] [% cgi.param('lastname') %]
+ Email: [% cgi.param('email') %]
+ Mozilla Space: [% cgi.param('mozspace') || "-" %]
+ Team/Department: [% cgi.param('teamcode') %]
+
+:: Recipient
+
+[% IF cgi.param("purpose") == "Mozillian Recognition" %]
+This [% terms.bug %] needs recipient shipping information: [% cgi.param("recognition_shipping") ? "Yes" : "No" %]
+This [% terms.bug %] needs recipient size information: [% cgi.param("recognition_sizing") ? "Yes" : "No" %]
+[% END %]
+
+ Name: [%+ cgi.param("shiptofirstname") +%] [%+ cgi.param("shiptolastname") +%]
+ Email: [%+ cgi.param("shiptoemail") +%]
+[% IF cgi.param("shiptoaddress1") %]
+ Address:
+ [%+ cgi.param("shiptoaddress1") +%]
+ [%+ cgi.param("shiptoaddress2") +%]
+ [%+ cgi.param("shiptocity") +%] [%+ cgi.param("shiptostate") +%] [%+ cgi.param("shiptopostcode") +%]
+ [%+ cgi.param("shiptocountry") %]
+ Phone: [% cgi.param("shiptophone") %]
+ Personal ID/RUT: [% cgi.param("shiptoidrut") || "-" %]
+[% END %]
+
+[% IF cgi.param("comment") %]
+:: Comments
+
+[%+ cgi.param("comment") %]
+[% END %]
+
diff --git a/extensions/BMO/template/en/default/bug/create/comment-user-engagement.txt.tmpl b/extensions/BMO/template/en/default/bug/create/comment-user-engagement.txt.tmpl
new file mode 100644
index 000000000..cff8f23b8
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/comment-user-engagement.txt.tmpl
@@ -0,0 +1,36 @@
+[%# 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.
+ #%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi +%]
+>>Project/Request Title:
+[%+ cgi.param('short_desc') %]
+
+>>Project Goals:
+[%+ cgi.param('goals') %]
+
+>>Who are you trying to reach?:
+[%+ cgi.param("audience") %]
+
+>>Localization:
+[%+ cgi.param("localization") %]
+
+>>Destination URL:
+[%+ cgi.param("bug_file_loc") %]
+
+>>Timing:
+[%+ cgi.param("timing_date") %]
+
+>>Success:
+[%+ cgi.param("success") %]
+
+>>Mozilla Goal:
+[%+ cgi.param("mozilla_goal") %]
+
+>>Points of Contact:
+[%+ cgi.param('cc') || 'Not provided' %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-automative.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-automative.html.tmpl
new file mode 100644
index 000000000..cbe2da910
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-automative.html.tmpl
@@ -0,0 +1,276 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% inline_style = BLOCK %]
+#automative_form {
+ padding: 10px;
+}
+#automative_form .required:after {
+ content: " *";
+ color: red;
+}
+#automative_form .field_label {
+ font-weight: bold;
+}
+#automative_form .field_desc {
+ padding-bottom: 3px;
+}
+#automative_form .field_desc,
+#automative_form .head_desc {
+ width: 600px;
+ word-wrap: normal;
+}
+#automative_form .head_desc {
+ padding-top: 5px;
+ padding-bottom: 12px;
+}
+#automative_form .form_section {
+ margin-bottom: 10px;
+}
+#automative_form textarea {
+ font-family: inherit;
+ font-size: inherit;
+}
+#automative_form em {
+ font-size: 1em;
+}
+.yui-calcontainer {
+ z-index: 2;
+}
+[% END %]
+
+[% inline_javascript = BLOCK %]
+function validateAndSubmit() {
+ 'use strict';
+ var alert_text = '';
+ var requiredLabels = YAHOO.util.Selector.query('label.required');
+ if (requiredLabels) {
+ requiredLabels.forEach(function (label) {
+ var name = label.getAttribute('for');
+ var ids = YAHOO.util.Selector.query(
+ '#automative_form *[name="' + name + '"]'
+ ).map(function (e) {
+ return e.id
+ });
+
+ if (ids && ids[0]) {
+ if (!isFilledOut(ids[0])) {
+ var desc = label.textContent || name;
+ alert_text +=
+ "Please enter a value for " +
+ desc.replace(/[\r\n]+/, "").replace(/\s+/g, " ") +
+ "\n";
+ }
+ }
+ });
+ }
+
+ if (alert_text != '') {
+ alert(alert_text);
+ return false;
+ }
+ return true;
+}
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Automation Request Form"
+ style = inline_style
+ javascript = inline_javascript
+ javascript_urls = [ 'extensions/BMO/web/js/form_validate.js',
+ 'js/field.js', 'js/util.js' ]
+ yui = [ "autocomplete", "calendar", "selector" ]
+%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+
+<form id="automative_form" method="post" action="post_bug.cgi"
+ enctype="multipart/form-data" onSubmit="return validateAndSubmit();">
+ <input type="hidden" name="format" value="automative">
+ <input type="hidden" name="product" value="Testing">
+ <input type="hidden" name="component" value="General">
+ <input type="hidden" name="rep_platform" value="All">
+ <input type="hidden" name="op_sys" value="Other">
+ <input type="hidden" name="version" value="unspecified">
+ <input type="hidden" name="bug_severity" id="bug_severity" value="normal">
+ <input type="hidden" name="token" value="[% token FILTER html %]">
+ <input type="hidden" name="assigned_to" value="jgriffin@mozilla.com">
+
+ <div class="head_desc">
+ Welcome to the Automation Request Form!
+ </div>
+
+ <div class="form_section">
+ <label for="short_desc" class="field_label required">Summary</label>
+ <div class="field_desc">
+ One-line summary of the problem you'd like automation to help solve
+ </div>
+ <input type="text" name="short_desc" id="short_desc" size="80">
+ </div>
+
+ <div class="form_section">
+ <label for="desc_problem" class="field_label required">Problem</label>
+ <div class="field_desc">
+ Detailed description of the problem
+ </div>
+ <textarea id="desc_problem" name="desc_problem"
+ cols="80" rows="5"></textarea>
+ </div>
+
+ <div class="form_section">
+ <label for="desc_solution" class="field_label required">Solution</label>
+ <div class="field_desc">
+ Detailed description of the proposed automation solution
+ </div>
+ <textarea id="desc_solution" name="desc_solution"
+ cols="80" rows="5"></textarea>
+ </div>
+
+ <div class="form_section">
+ <label for="desc_top_level_goal" class="field_label required">Top Level
+ Goal</label>
+ <div class="field_desc">Describe the top-level project goal which this is
+ supporting</div>
+ <textarea id="desc_top_level_goal" name="desc_top_level_goal" cols="80"
+ rows="5"></textarea>
+ </div>
+
+ <div class="form_section">
+ <label for="existing_bug" class="field_label">Existing [% terms.Bug %]
+ number </label>
+ <div class="field_desc"> Existing [% terms.bug %] (if any) </div>
+ <input type="text" name="existing_bug" id="existing_bug" size="80">
+ </div>
+
+ <div class="form_section">
+ <label for="per_commit" class="field_label">Run per-commit?</label>
+ <div class="field_desc">
+ Does this automation need to be run per-commit and report to TBPL? Can it
+ be run less frequently?
+ </div>
+ <input type="text" name="per_commit" id="per_commit" size="80">
+ </div>
+
+ <div class="form_section">
+ <label for="desc_data_produce" class="field_label">Data capture?</label>
+ <div class="field_desc">If this automation will report data other than
+ pass/fail (e.g. some sort of performance metric), describe the data that
+ you'd like to have the automation produce. Do we already have a method of
+ capturing this kind of data, or do we need to develop one?</div>
+ <textarea id="desc_data_produce" name="desc_data_produce" cols="80"
+ rows="5"></textarea>
+ </div>
+
+ <div class="form_section">
+ <label for="prototype_date" class="field_label">Prototype Date</label>
+ <div class="field_desc">
+ When is a prototype needed?
+ </div>
+ <input name="prototype_date" size="20" id="prototype_date" value=""
+ onchange="updateCalendarFromField(this)">
+ <button type="button" class="calendar_button"
+ id="button_calendar_prototype_date"
+ onclick="showCalendar('prototype_date')">
+ <span>Calendar</span>
+ </button>
+ <div id="con_calendar_prototype_date"></div>
+ <script type="text/javascript">
+ createCalendar('prototype_date')
+ </script>
+ </div>
+
+ <div class="form_section">
+ <label for="production_date" class="field_label">Production Date</label>
+ <div class="field_desc">
+ When is a finished project running in production needed?
+ </div>
+ <input name="production_date" size="20" id="production_date" value=""
+ onchange="updateCalendarFromField(this)">
+ <button type="button" class="calendar_button"
+ id="button_calendar_production_date"
+ onclick="showCalendar('production_date')">
+ <span>Calendar</span>
+ </button>
+ <div id="con_calendar_production_date"></div>
+ <script type="text/javascript">
+ createCalendar('production_date')
+ </script>
+ </div>
+
+ <div class="form_section">
+ <label for="most_valuable_piece" class="field_label">Most Valuable
+ Piece?</label>
+ <div class="field_desc">If there are multiple pieces, tests, or features in
+ the proposed automation, what is the single most valuable piece?</div>
+ <input type="text" name="most_valuable_piece" id="most_valuable_piece"
+ size="80">
+ </div>
+
+ <div class="form_section">
+ <label for="responsible_engineer" class="field_label">Responsible
+ Engineer</label>
+ <div class="field_desc">
+ Which engineer is responsible for working with the automation engineer for
+ information, support, and troubleshooting?
+ </div>
+ [% INCLUDE global/userselect.html.tmpl
+ id => "responsible_engineer"
+ name => "responsible_engineer"
+ value => ""
+ size => 80
+ classes => ["bz_userfield"]
+ %]
+ </div>
+
+ <div class="form_section">
+ <label for="manager" class="field_label">Manager</label>
+ <div class="field_desc">
+ Which manager/project manager is responsible for issues related to
+ milestones and priorities?
+ </div>
+ [% INCLUDE global/userselect.html.tmpl
+ id => "manager"
+ name => "manager"
+ value => ""
+ size => 80
+ classes => ["bz_userfield"]
+ %]
+ </div>
+
+ <div class="form_section">
+ <label for="other_teams" class="field_label">Other Teams</label>
+ <div class="field_desc">
+ What other teams are involved and are there any other external
+ dependencies?
+ </div>
+ <textarea id="other_teams" name="other_teams" cols="80"
+ rows="5"></textarea>
+ </div>
+
+ <div class="form_section">
+ <label for="additional_info" class="field_label">Additional
+ Information</label>
+ <div class="field_desc">
+ Additional information
+ </div>
+ <textarea id="additional_info" name="additional_info" cols="80"
+ rows="5"></textarea>
+ </div>
+
+ <input type="submit" id="commit" value="Submit">
+
+ <p>
+ [ <span class="required_star">*</span> <span class="required_explanation">
+ Required Field</span> ]
+ </p>
+</form>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-creative.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-creative.html.tmpl
new file mode 100644
index 000000000..0c4fad8d6
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-creative.html.tmpl
@@ -0,0 +1,259 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% inline_style = BLOCK %]
+#creative_form {
+ padding: 10px;
+}
+#creative_form .required:after {
+ content: " *";
+ color: red;
+}
+#creative_form .field_label {
+ font-weight: bold;
+}
+#creative_form .field_desc {
+ padding-bottom: 3px;
+}
+#creative_form .field_desc,
+#creative_form .head_desc {
+ width: 600px;
+ word-wrap: normal;
+}
+#creative_form .head_desc {
+ padding-top: 5px;
+ padding-bottom: 12px;
+}
+#creative_form .form_section {
+ margin-bottom: 10px;
+}
+#creative_form textarea {
+ font-family: inherit;
+ font-size: inherit;
+}
+#creative_form em {
+ font-size: 1em;
+}
+.yui-calcontainer {
+ z-index: 2;
+}
+[% END %]
+
+[% inline_javascript = BLOCK %]
+function validateAndSubmit() {
+ var alert_text = '';
+ if (!isFilledOut('overview')) alert_text += 'Please enter a value for Project Overview.\n';
+ if (!isFilledOut('short_desc')) alert_text += 'Please enter a value for Request Title.\n';
+ if (!isFilledOut('specs')) alert_text += 'Please enter a value for Creative Specs.\n';
+ if (!isFilledOut('cta_design')) alert_text += 'Please enter a value for CTA Design.\n';
+ if (!isFilledOut('cf_due_date')) alert_text += 'Please enter a value for the creative due date.\n';
+ if (!isFilledOut('goal')) alert_text += 'Please select a value for Mozilla Goal.\n';
+ if (YAHOO.util.Dom.get('goal').value == 'Other') {
+ if (!isFilledOut('goal_other')) alert_text += 'Please select a value for Mozilla Goal Other.\n';
+ }
+ if (YAHOO.util.Dom.get('type_copy').checked == false
+ && YAHOO.util.Dom.get('type_design').checked == false
+ && YAHOO.util.Dom.get('type_video').checked == false
+ && YAHOO.util.Dom.get('type_other').checked == false)
+ {
+ alert_text += 'Please select at least one type of help needed.\n';
+ }
+ if (YAHOO.util.Dom.get('type_other').checked == true) {
+ if (!isFilledOut('type_other_text')) alert_text += 'Please enter a value for other type of help needed.\n';
+ }
+ if (alert_text != '') {
+ alert(alert_text);
+ return false;
+ }
+ return true;
+}
+function toggleGoalOther() {
+ var goal_select = YAHOO.util.Dom.get('goal');
+ if (goal_select.options[goal_select.selectedIndex].value == 'Other') {
+ YAHOO.util.Dom.removeClass('goal_other','bz_default_hidden');
+ }
+ else {
+ YAHOO.util.Dom.addClass('goal_other','bz_default_hidden');
+ }
+}
+function toggleTypeOther(element) {
+ var other_text = YAHOO.util.Dom.get('type_other_text');
+ if (element.checked == true) {
+ other_text.disabled = false;
+ other_text.focus();
+ }
+ else {
+ other_text.disabled = true;
+ }
+}
+
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Creative Initiation Form"
+ style = inline_style
+ javascript = inline_javascript
+ javascript_urls = [ 'extensions/BMO/web/js/form_validate.js',
+ 'js/field.js', 'js/util.js' ]
+ yui = [ "autocomplete", "calendar" ]
+%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+
+<form id="creative_form" method="post" action="post_bug.cgi" enctype="multipart/form-data"
+ onSubmit="return validateAndSubmit();">
+ <input type="hidden" name="format" value="creative">
+ <input type="hidden" name="product" value="Marketing">
+ <input type="hidden" name="component" value="Design">
+ <input type="hidden" name="rep_platform" value="All">
+ <input type="hidden" name="op_sys" value="Other">
+ <input type="hidden" name="version" value="unspecified">
+ <input type="hidden" name="bug_severity" id="bug_severity" value="normal">
+ <input type="hidden" name="token" value="[% token FILTER html %]">
+
+<img title="Creative Initiation Form" src="extensions/BMO/web/images/creative.png">
+
+<div class="head_desc">
+ Have a new project or campaign that requires copy, design, video or other awesomeness
+ from your friendly neighborhood Brand Team? Please use this form to tell us about it
+ and we'll get back to you with next steps as soon as possible.
+</div>
+
+<div class="form_section">
+ <label for="short_desc" class="field_label required">Project / Request Title</label>
+ <div class="field_desc">
+ Describe your project or request in a few words or a short phrase.
+ </div>
+ <input type="text" name="short_desc" id="short_desc" size="80">
+</div>
+
+<div class="form_section">
+ <label for="overview" class="field_label required">Project Overview</label>
+ <div class="field_desc">
+ Briefly describe the background, goals and objectives for this project.
+ </div>
+ <textarea id="overview" name="overview" cols="80" rows="5"></textarea>
+</div>
+
+<div class="form_section">
+ <label for="specs" class="field_label required">Creative Specs and Deliverables</label>
+ <div class="field_desc">
+ Select what sort of help you need (check at least one or more)
+ </div>
+ <input type="checkbox" name="type_copy" id="type_copy" value="1">Copy<br>
+ <input type="checkbox" name="type_design" id="type_design" value="1">Design<br>
+ <input type="checkbox" name="type_video" id="type_video" value="1">Video<br>
+ <input type="checkbox" name="type_other" id="type_other" value="1" onchange="toggleTypeOther(this);">Other&nbsp;&nbsp;
+ <input type="text" name="type_other_text" id="type_other_text"><br>
+ <br>
+ <div class="field_desc">
+ <strong class="required">Specs</strong><br>
+ What is the final deliverable and what format should it be delivered in?
+ Please include information on the format, image/file size, word count, video length,
+ etc. We like details here.
+ </div>
+ <textarea id="specs" name="specs" cols="80" rows="5"></textarea>
+ <br>
+ <br>
+ <div class="field_desc">
+ <strong class="required">CTAs and design directions</strong><br>
+ Provide as much information as possible. Make sure to include links to documents with copy,
+ mock-ups, wireframes, or any other information or assets that could help with direction.
+ </div>
+ <textarea id="cta_design" name="cta_design" cols="80" rows="5"></textarea>
+</div>
+
+<div class="form_section">
+ <label for="cf_due_date" class="field_label required">Creative Due Date</label>
+ <div class="field_desc">
+ Working backwards from your launch/go-live date, when do you need final assets?
+ </div>
+ <input name="cf_due_date" size="20" id="cf_due_date" value=""
+ onchange="updateCalendarFromField(this)">
+ <button type="button" class="calendar_button"
+ id="button_calendar_cf_due_date"
+ onclick="showCalendar('cf_due_date')">
+ <span>Calendar</span>
+ </button>
+ <div id="con_calendar_cf_due_date"></div>
+ <script type="text/javascript">
+ createCalendar('cf_due_date')
+ </script>
+</div>
+
+<div class="form_section">
+ <label for="launch_date" class="field_label">Launch Date</label>
+ <div class="field_desc">
+ When will your project go forth into the world?
+ </div>
+ <input name="launch_date" size="20" id="launch_date" value=""
+ onchange="updateCalendarFromField(this)">
+ <button type="button" class="calendar_button"
+ id="button_calendar_launch_date"
+ onclick="showCalendar('launch_date')">
+ <span>Calendar</span>
+ </button>
+ <div id="con_calendar_launch_date"></div>
+ <script type="text/javascript">
+ createCalendar('launch_date')
+ </script>
+</div>
+
+<div class="form_section">
+ <label for="goal" class="field_label required">Mozilla Goal</label>
+ <div class="field_desc">
+ Which high-level Mozilla goal does this project support?
+ </div>
+ <select id="goal" name="goal"
+ onchange="toggleGoalOther();">
+ <option value="">Please select..</option>
+ <option value="Firefox OS">Firefox OS</option>
+ <option value="Firefox Browser">Firefox Browser</option>
+ <option value="Million Mozillians">Million Mozillians</option>
+ <option value="Services">Services</option>
+ <option value="Org Support">Org Support</option>
+ <option value="Other">Other</option>
+ </select>
+ <br>
+ <input type="text" name="goal_other" id="goal_other" size="40"
+ class="bz_default_hidden" value="">
+</div>
+
+<div class="form_section">
+ <label for="cc" class="field_label">Points of Contact</label>
+ <div class="field_desc">
+ Who should be kept in the loop and informed of updates (and CC'd on the [% terms.bug %])?
+ </div>
+ [% INCLUDE global/userselect.html.tmpl
+ id => "cc"
+ name => "cc"
+ value => ""
+ size => 80
+ classes => ["bz_userfield"]
+ multiple => 5
+ %]
+</div>
+
+<div class="head_desc">
+ Thanks! Once you hit submit, your request will go off into the vortex of creative magic.
+ (Actually, it goes to [% terms.Bugzilla %], but that doesn't sound as cool.) We'll be in touch soon
+ with next steps and to let you know if we need any additional info.
+</div>
+
+<input type="submit" id="commit" value="Submit">
+
+<p>
+ [ <span class="required_star">*</span> <span class="required_explanation">Required Field</span> ]
+</p>
+
+</form>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-dev-engagement-event.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-dev-engagement-event.html.tmpl
new file mode 100644
index 000000000..ef6737098
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-dev-engagement-event.html.tmpl
@@ -0,0 +1,537 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% inline_css = BLOCK %]
+ #bug_form {
+ max-width: 50em;
+ }
+
+ #bug_form th {
+ text-align: left;
+ padding-top: 0.5em;
+ }
+
+ #bug_form .section-head {
+ font-size: larger;
+ padding-top: 1em;
+ }
+
+ #bug_form th:not(.section-head), #bug_form td {
+ padding-left: 2em;
+ }
+
+ #bug_form .mandatory {
+ color: red;
+ }
+
+ #bug_form .blurb {
+ font-style: italic;
+ }
+
+ #bug_form .wide {
+ width: 40em;
+ }
+
+ #bug_form input[disabled] {
+ background: transparent;
+ }
+[% END %]
+
+[% inline_js = BLOCK %]
+// <script>
+ function onRequestOtherChange() {
+ var cb = document.getElementById('request-other');
+ var input = document.getElementById('request-other-text');
+ input.disabled = !cb.checked;
+ if (cb.checked)
+ input.focus();
+ }
+
+ function onRequestSponsorshipChange() {
+ var cb = document.getElementById('request-sponsorship');
+ if (cb.checked) {
+ YAHOO.util.Dom.removeClass('sponsorship-suggestion-fields', 'bz_default_hidden');
+ }
+ else {
+ YAHOO.util.Dom.addClass('sponsorship-suggestion-fields', 'bz_default_hidden');
+ }
+ }
+
+ function onProductOtherChange() {
+ var cb = document.getElementById('product-other');
+ var input = document.getElementById('product-other-text');
+ input.disabled = !cb.checked;
+ if (cb.checked)
+ input.focus();
+ }
+
+ function onSubmit() {
+ if (document.getElementById('request-other').checked
+ && !isFilledOut('request-other-text')
+ ) {
+ document.getElementById('request-other').checked = false;
+ onRequestOtherChange();
+ }
+
+ var alert_text = '';
+
+ if (!isFilledOut('name'))
+ alert_text += "Please enter your name.\n";
+ if (!isFilledOut('email'))
+ alert_text += "Please enter your email address.\n";
+ if (!isFilledOut('role'))
+ alert_text += "Please enter your role.\n";
+
+ if (!isFilledOut('event'))
+ alert_text += "Please enter the event name.\n";
+ if (!isFilledOut('start_date'))
+ alert_text += "Please enter the event start date.\n";
+ if (!isFilledOut('end_date'))
+ alert_text += "Please enter the event end date.\n";
+ if (!isFilledOut('attendees'))
+ alert_text += "Please enter number of expected attendees.\n";
+ if (!isFilledOut('audience'))
+ alert_text += "Please enter primary audience.\n";
+
+
+ var wb = '';
+ if (document.getElementById('request-keynote').checked)
+ wb += '[keynote] ';
+ if (document.getElementById('request-talk').checked)
+ wb += '[talk] ';
+ if (document.getElementById('request-workshop').checked)
+ wb += '[workshop] ';
+ if (document.getElementById('request-sponsorship').checked)
+ wb += '[sponsorship] ';
+ if (document.getElementById('request-other').checked)
+ wb += '[other] ';
+ if (wb == '')
+ alert_text += "Please select what you're requesting.\n";
+
+ if (alert_text != '') {
+ alert(alert_text);
+ return false;
+ }
+
+ document.getElementById('status_whiteboard').value = wb.replace(/ $/, '');
+ var summary = document.getElementById('event').value + ', ' + long_start_date();
+ var loc = document.getElementById('location').value;
+ if (loc)
+ summary = summary + ' (' + loc + ')';
+ document.getElementById('short_desc').value = summary;
+ document.getElementById('bug_file_loc').value = document.getElementById('link').value;
+ document.getElementById('cf_due_date').value = document.getElementById('start_date').value;
+
+ return true;
+ }
+
+ function long_start_date() {
+ var ymd = document.getElementById('start_date').value.split('-');
+ if (ymd.length != 3)
+ return '';
+ var month = YAHOO.bugzilla.calendar_start_date.cfg.getProperty('MONTHS_LONG')[ymd[1] - 1];
+ return month + ' ' + ymd[0];
+ }
+
+ YAHOO.util.Event.onDOMReady(function() {
+ createCalendar('start_date');
+ createCalendar('end_date');
+ onRequestOtherChange();
+ onRequestSponsorshipChange();
+ onProductOtherChange();
+ });
+// </script>
+[% END %]
+
+[% mandatory = BLOCK %]
+ <span class="mandatory" title="Mandatory">*</span>
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Developer Events Request Form"
+ style = inline_css
+ style_urls = [ 'skins/standard/enter_bug.css' ]
+ javascript = inline_js
+ javascript_urls = [ 'extensions/BMO/web/js/form_validate.js', 'js/field.js', 'js/util.js' ]
+ yui = [ 'calendar' ]
+%]
+
+<h2>Developer Events Request Form</h2>
+
+<form method="post" action="post_bug.cgi" id="bug_form" class="enter_bug_form"
+ enctype="multipart/form-data" onsubmit="return onSubmit();">
+<input type="hidden" name="format" value="dev-engagement-event">
+<input type="hidden" name="product" value="Developer Engagement">
+<input type="hidden" name="short_desc" id="short_desc" value="">
+<input type="hidden" name="component" value="Events Request">
+<input type="hidden" name="rep_platform" value="All">
+<input type="hidden" name="op_sys" value="All">
+<input type="hidden" name="priority" value="--">
+<input type="hidden" name="version" value="unspecified">
+<input type="hidden" name="bug_severity" id="bug_severity" value="normal">
+<input type="hidden" name="comment" id="comment" value="">
+<input type="hidden" name="status_whiteboard" id="status_whiteboard" value="">
+<input type="hidden" name="bug_file_loc" id="bug_file_loc" value="">
+<input type="hidden" name="cf_due_date" id="cf_due_date" value="">
+<input type="hidden" name="groups" id="groups" value="mozilla-employee-confidential">
+<input type="hidden" name="token" value="[% token FILTER html %]">
+
+<table id="bug_form">
+
+<tr>
+ <td>
+ <p>
+ Hi! Thanks so much for asking Mozilla to participate at your event!
+ </p>
+ <p>
+ The Developer Events Team evaluates each request individually, based on
+ multiple criteria, including quarterly goals and priorities. We meet at
+ least biweekly, and this form is designed to gather all the information
+ we need to evaluate each request at these meetings. Please take a minute
+ to fill it out thoroughly so we can process your request as soon as
+ possible.
+ </p>
+ <p>
+ Please review our <a href="https://wiki.mozilla.org/Engagement/Developer_Engagement/Event_request_guidelines">
+ event request guidelines</a> for information about how we evaluate requests.
+ </p>
+ </td>
+</tr>
+
+<tr>
+ <th class="section-head">
+ First, tell us about yourself!
+ </th>
+</tr>
+
+<tr>
+ <th>
+ What is your name? [% mandatory FILTER none %]
+ </th>
+</tr>
+<tr>
+ <td>
+ <input type="text" name="name" id="name" size="40" class="wide"
+ value="[% user.name FILTER html %]">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ Please provide your email address. [% mandatory FILTER none %]
+ </th>
+</tr>
+<tr>
+ <td>
+ <input type="text" name="email" id="email" size="40" class="wide"
+ value="[% user.login FILTER html %]">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ What is your role in relation to this event? [% mandatory FILTER none %]
+ </th>
+</tr>
+<tr>
+ <td>
+ <div class="blurb">
+ eg. organizer, speaker/atendee (past), speaker/attendee (current), etc.
+ </div>
+ <input type="text" name="role" id="role" size="40" class="wide">
+ </td>
+</tr>
+
+<tr>
+ <th class="section-head">
+ Let's start with the basics.
+ </th>
+</tr>
+
+<tr>
+ <th>
+ Event Name [% mandatory FILTER none %]
+ </th>
+</tr>
+<tr>
+ <td>
+ <input type="text" name="event" id="event" size="40" class="wide">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ Start Date [% mandatory FILTER none %]
+ </th>
+</tr>
+<tr>
+ <td>
+ <input type="text" name="start_date" id="start_date" size="15" class="date"
+ onchange="updateCalendarFromField(this)">
+ <button type="button" class="calendar_button"
+ id="button_calendar_start_date"
+ onclick="showCalendar('start_date')">
+ <span>Calendar</span>
+ </button>
+ <div id="con_calendar_start_date"></div>
+ </td>
+</tr>
+
+<tr>
+ <th>
+ End Date [% mandatory FILTER none %]
+ </th>
+</tr>
+<tr>
+ <td>
+ <input type="text" name="end_date" id="end_date" size="15" class="date"
+ onchange="updateCalendarFromField(this)">
+ <button type="button" class="calendar_button"
+ id="button_calendar_end_date"
+ onclick="showCalendar('end_date')">
+ <span>Calendar</span>
+ </button>
+ <div id="con_calendar_end_date"></div>
+ </td>
+</tr>
+
+<tr>
+ <th>
+ Event Location
+ </th>
+</tr>
+<tr>
+ <td>
+ <div class="blurb">
+ Include city, state, and country. Please write "Multiple" if this event
+ takes place across several locations.
+ </div>
+ <input type="text" name="location" id="location" size="40" class="wide">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ Venue
+ </th>
+</tr>
+<tr>
+ <td>
+ <div class="blurb">
+ What is the name of the venue where your event will be held? Enter TBD if
+ you don't know yet.
+ </div>
+ <input type="text" name="venue" id="venue" size="40" class="wide">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ Weblink
+ </th>
+</tr>
+<tr>
+ <td>
+ <div class="blurb">
+ Weblink to the event site, Eventbrite page, Lanyrd page, Meetup page, etc.
+ </div>
+ <input type="text" name="link" id="link" size="40" class="wide">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ Number of expected attendees [% mandatory FILTER none %]
+ </th>
+</tr>
+<tr>
+ <td>
+ <input type="text" name="attendees" id="attendees" size="15">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ Please give a [short] description of the event. [% mandatory FILTER none %]
+ </th>
+</tr>
+<tr>
+ <td>
+ <div class="blurb">
+ Include track topics, presentation topics, event format.
+ </div>
+ <textarea name="desc" id="desc" rows="10" cols="40" class="wide"></textarea>
+ </td>
+</tr>
+
+<tr>
+ <th>
+ Who is the primary audience for this event? [% mandatory FILTER none %]
+ </th>
+</tr>
+<tr>
+ <td>
+ <div class="blurb">
+ Developers (specify coding language and platform), business development,
+ marketing associates, corporate executives, etc.
+ </div>
+ <input type="text" name="audience" id="audience" size="40" class="wide">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ Which Mozilla products/projects are most relevant to this event? [% mandatory FILTER none %]
+ </th>
+</tr>
+<tr>
+ <td>
+ <div class="blurb">
+ Please select all that apply.
+ See <a href="https://www.mozilla.org/en-US/products/" target="_blank">mozilla.org/products</a>
+ for more information about Mozilla products.
+ </div>
+ <input type="checkbox" name="product-fxos" id="product-fxos">
+ <label for="product-fxos">Firefox OS</label><br>
+ <input type="checkbox" name="product-fx" id="product-fx">
+ <label for="product-fx">Firefox Web Browser</label><br>
+ <input type="checkbox" name="product-webmaker" id="product-webmaker">
+ <label for="product-webmaker">Webmaker</label><br>
+ <input type="checkbox" name="product-persona" id="product-persona">
+ <label for="product-persona">Persona</label><br>
+ <input type="checkbox" name="product-marketplace" id="product-marketplace">
+ <label for="product-marketplace">Marketplace</label><br>
+ <input type="checkbox" name="product-tb" id="product-tb">
+ <label for="product-tb">Thunderbird</label><br>
+ <input type="checkbox" name="product-fow" id="product-fow">
+ <label for="product-fow">The Free and Open Web</label><br>
+ <input type="checkbox" name="product-other" id="product-other" onchange="onProductOtherChange()">
+ <label for="product-other">Other:</label>
+ <input type="text" name="product-other-text" id="product-other-text" size="40" disabled>
+ </td>
+</tr>
+
+<tr>
+ <th class="section-head">
+ Tell us more about what you're looking for!
+ </th>
+</tr>
+
+<tr>
+ <th>
+ What are you requesting from Mozilla? [% mandatory FILTER none %]
+ </th>
+</tr>
+<tr>
+ <td>
+ <div class="blurb">
+ Please select all that apply.
+ </div>
+ <input type="checkbox" name="request-keynote" id="request-keynote">
+ <label for="request-keynote">Keynote Presentation</label><br>
+ <input type="checkbox" name="request-talk" id="request-talk">
+ <label for="request-talk">Talk Presentation (non-keynote)</label><br>
+ <input type="checkbox" name="request-workshop" id="request-workshop">
+ <label for="request-workshop">Workshop</label><br>
+ <input type="checkbox" name="request-sponsorship" id="request-sponsorship" onchange="onRequestSponsorshipChange()">
+ <label for="request-sponsorship">Sponsorship</label><br>
+ <input type="checkbox" name="request-other" id="request-other" onchange="onRequestOtherChange()">
+ <label for="request-other">Other:</label>
+ <input type="text" name="request-other-text" id="request-other-text" size="40" disabled>
+ </td>
+</tr>
+
+<tbody id="sponsorship-suggestion-fields">
+ <tr>
+ <th>
+ If requesting sponsorship, what amount/level do you suggest?
+ </th>
+ </tr>
+ <tr>
+ <td>
+ <input type="text" name="sponsorship-suggestion" id="sponsorship-suggestion" size="40" class="wide">
+ </td>
+ </tr>
+</tbody>
+
+<tr>
+ <th>
+ Please list the names of anyone from Mozilla who are already registered to
+ attend, speak, or participate in this event.
+ </th>
+</tr>
+<tr>
+ <td>
+ <input type="text" name="mozillians" id="mozillians" size="40" class="wide">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ Are you requesting a specific person to present or participate at this
+ event? If so, please list their name(s).
+ </th>
+</tr>
+<tr>
+ <td>
+ <input type="text" name="specific" id="specific" size="40" class="wide">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ If this individual is unable to attend/speak/participate in this event, is
+ there anyone else you would like to request?
+ </th>
+</tr>
+<tr>
+ <td>
+ <input type="text" name="fallback" id="fallback" size="40" class="wide">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ Please upload a Sponsorship Prospectus if you have one.
+ </th>
+</tr>
+<tr>
+ <td>
+ <input type="file" name="data" id="data" size="40">
+ <input type="hidden" name="contenttypemethod" value="autodetect">
+ <input type="hidden" id="description" name="description" value="Sponsorship Prospectus">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ Anything else that may help us review this request?
+ </th>
+</tr>
+<tr>
+ <td>
+ <input type="text" name="else" id="else" size="40" class="wide">
+ </td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+</tr>
+<tr>
+ <td>
+ <input type="submit" id="commit" value="Submit Request">
+ </td>
+</tr>
+
+</table>
+
+</form>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-doc.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-doc.html.tmpl
new file mode 100644
index 000000000..5b75976d9
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-doc.html.tmpl
@@ -0,0 +1,222 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% inline_style = BLOCK %]
+#doc_form th {
+ text-align: right;
+}
+
+#short_desc, #details {
+ width: 100%;
+}
+[% END %]
+
+[% inline_javascript = BLOCK %]
+function validateAndSubmit() {
+ var alert_text = '';
+ if (!isFilledOut('type')) alert_text += 'Please select the "Request Type".\n';
+ if (!isFilledOut('short_desc')) alert_text += 'Please enter a "Summary".\n';
+ if (!isFilledOut('gecko')) alert_text += 'Please select the "Gecko Version".\n';
+ if (!isFilledOut('details')) alert_text += 'Please enter some "Details".\n';
+ if (alert_text != '') {
+ alert(alert_text);
+ return false;
+ }
+ return true;
+}
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Developer Documentation Request"
+ style = inline_style
+ javascript = inline_javascript
+ javascript_urls = [ 'extensions/BMO/web/js/form_validate.js',
+ 'js/field.js', 'js/util.js', 'js/bug.js' ]
+ yui = [ 'autocomplete', 'datatable', 'button' ]
+%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+
+<h1>Developer Documentation Request</h1>
+
+<p>
+ Use this form to request <b>new documentation</b> or <b>corrections</b> to existing documentation.<br>
+ [ <span class="required_star">*</span> <span class="required_explanation">Required Fields</span> ]
+</p>
+
+<form method="post" action="post_bug.cgi" enctype="multipart/form-data"
+ onSubmit="return validateAndSubmit();">
+ <input type="hidden" name="format" value="doc">
+ <input type="hidden" name="product" value="Developer Documentation">
+ <input type="hidden" name="rep_platform" value="All">
+ <input type="hidden" name="op_sys" value="Other">
+ <input type="hidden" name="version" value="unspecified">
+ <input type="hidden" name="bug_severity" id="bug_severity" value="normal">
+ <input type="hidden" name="status_whiteboard" id="status_whiteboard" value="">
+ <input type="hidden" name="token" value="[% token FILTER html %]">
+
+<table id="doc_form">
+
+<tr>
+ <th class="required">Request Type</th>
+ <td>
+ <select name="type" id="type">
+ <option value="">Please select..</option>
+ <option value="New Documentation">New Documentation</option>
+ <option value="Correction" [% "selected" IF cgi.param('bug_file_loc') %]>Correction</option>
+ </select>
+ </td>
+</tr>
+
+<tr>
+ <th class="required">Topic</th>
+ <td>
+ <select name="component" id="component">
+ [% FOREACH component = product.components %]
+ <option value="[% component.name FILTER html %]"
+ [% " selected" IF component.name == "General" %]
+ title="[% component.description FILTER html %]">
+ [% component.name FILTER html %]
+ </option>
+ [% END %]
+ </select>
+ </td>
+</tr>
+
+<tr>
+ <th class="required">Summary</th>
+ <td>
+ Please provide a brief summary of what documentation you're requesting, or
+ what problem you're reporting in existing documentation:<br>
+ <input type="text" name="short_desc" id="short_desc" size="60">
+ </td>
+</tr>
+
+[% IF feature_enabled('jsonrpc') AND !cloned_bug_id %]
+ <tr id="possible_duplicates_container" class="bz_default_hidden">
+ <th>Possible<br>Duplicates:</th>
+ <td colspan="3">
+ <div id="possible_duplicates"></div>
+ <script type="text/javascript">
+ var dt_columns = [
+ { key: "id", label: "[% field_descs.bug_id FILTER js %]",
+ formatter: YAHOO.bugzilla.dupTable.formatBugLink },
+ { key: "summary",
+ label: "[% field_descs.short_desc FILTER js %]",
+ formatter: "text" },
+ { key: "status",
+ label: "[% field_descs.bug_status FILTER js %]",
+ formatter: YAHOO.bugzilla.dupTable.formatStatus },
+ { key: "update_token", label: '',
+ formatter: YAHOO.bugzilla.dupTable.formatCcButton }
+ ];
+ YAHOO.bugzilla.dupTable.addCcMessage = "Add Me to the CC List";
+ YAHOO.bugzilla.dupTable.init({
+ container: 'possible_duplicates',
+ columns: dt_columns,
+ product_name: '[% product.name FILTER js %]',
+ summary_field: 'short_desc',
+ options: {
+ MSG_LOADING: 'Searching for possible duplicates...',
+ MSG_EMPTY: 'No possible duplicates found.',
+ SUMMARY: 'Possible Duplicates'
+ }
+ });
+ </script>
+ </td>
+ </tr>
+[% END %]
+
+<tr>
+ <th>Page to Update</th>
+ <td>
+ <input type="text" name="bug_file_loc" id="short_desc" size="60"
+ value="[% bug_file_loc FILTER html %]">
+ </td>
+</tr>
+
+<tr>
+ <th>Technical Contact</th>
+ <td>
+ [% INCLUDE global/userselect.html.tmpl
+ id => "cc"
+ name => "cc"
+ value => ""
+ size => 60
+ classes => ["bz_userfield"]
+ multiple => 5
+ %]
+ <br>
+ <a href="https://developer.mozilla.org/en-US/docs/Project:Subject-matter_experts"
+ target="_blank" id="common_topic_experts">
+ List of common topic experts</a>
+ </td>
+</tr>
+
+<tr>
+ <th class="required">Gecko Version</th>
+ <td>
+ <select name="gecko" id="gecko">
+ [% FOREACH version = versions %]
+ <option value="[% version.name FILTER html %]"
+ [% " selected" IF version.name == "unspecified" %]>
+ [% version.name FILTER html %]
+ </option>
+ [% END %]
+ </select>
+ </td>
+</tr>
+
+<tr>
+ <th class="required">Details</th>
+ <td>
+ <textarea id="details" name="details" cols="50" rows="10"></textarea>
+ </td>
+</tr>
+
+<tr>
+ <th>Development [% terms.Bug %]</th>
+ <td>
+ <input type="text" id="blocked" name="blocked" size="10">
+ <i>Corresponding development [% terms.bug %].</i>
+ </td>
+</tr>
+
+<tr>
+ <th class="required">Urgency</th>
+ <td>
+ <select name="priority" id="priority">
+ <option value="P1">Immediately</option>
+ <option value="P2">Before Release</option>
+ <option value="P3">Before Aurora</option>
+ <option value="P4">Before Beta</option>
+ <option value="P5" selected>No Rush</option>
+ </select>
+ <br>
+ Due to the volume of requests, the documentation team can't commit to
+ meeting specific deadlines for given documentation requests, but we will do
+ our best.
+ </td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+ <td><input type="submit" id="commit" value="Submit Request"></td>
+</tr>
+
+</table>
+</form>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-employee-incident.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-employee-incident.html.tmpl
new file mode 100644
index 000000000..164dd482c
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-employee-incident.html.tmpl
@@ -0,0 +1,11 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/redirect.html.tmpl
+ url = "https://mozilla.service-now.com/com.glideapp.servicecatalog_cat_item_view.do?sysparm_id=4f9468ef184a30004a467ddd1a20df63"
+%]
diff --git a/extensions/BMO/template/en/default/bug/create/create-finance.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-finance.html.tmpl
new file mode 100644
index 000000000..fa8dc5f5b
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-finance.html.tmpl
@@ -0,0 +1,257 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% inline_style = BLOCK %]
+ #bug_form input[type=text], #bug_form input[type=file], #cc_autocomplete, #bug_form textarea {
+ width: 100%;
+ }
+[% END %]
+
+[% inline_js = BLOCK %]
+ var compdesc = new Array();
+ [% FOREACH comp = product.components %]
+ compdesc['[% comp.name FILTER js %]'] = '[% comp.description FILTER js %]';
+ [% END %]
+ function showCompDesc(component) {
+ var value = component.value;
+ document.getElementById('comp_description').innerHTML = compdesc[value];
+ }
+
+ function onSubmit() {
+ var alert_text = '';
+ if (!isFilledOut('component'))
+ alert_text += "Please select a value for request type.\n";
+ if (!isFilledOut('short_desc'))
+ alert_text += "Please enter a value for the summary.\n";
+ if (!isFilledOut('team_priority'))
+ alert_text += "Please select a value for team priority.\n";
+ if (!isFilledOut('signature_time'))
+ alert_text += "Please enter a value for signture timeframe.\n";
+ if (!isFilledOut('other_party'))
+ alert_text += "Please enter a value for the name of other party.\n";
+ if (!isFilledOut('business_obj'))
+ alert_text += "Please enter a value for business objective.\n";
+ if (!isFilledOut('what_purchase'))
+ alert_text += "Please enter a value for what you are purchasing.\n";
+ if (!isFilledOut('why_purchase'))
+ alert_text += "Please enter a value for why the purchase is needed.\n";
+ if (!isFilledOut('risk_purchase'))
+ alert_text += "Please enter a value for the risk if not purchased.\n";
+ if (!isFilledOut('alternative_purchase'))
+ alert_text += "Please enter a value for the purchase alternative.\n";
+ if (!isFilledOut('total_cost'))
+ alert_text += "Please enter a value for total cost.\n";
+ if (!isFilledOut('attachment'))
+ alert_text += "Please enter an attachment.\n";
+
+ if (alert_text != '') {
+ alert(alert_text);
+ return false;
+ }
+
+ return true;
+ }
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Finance"
+ style = inline_style
+ style_urls = [ 'skins/standard/enter_bug.css' ]
+ javascript = inline_js
+ javascript_urls = [ 'extensions/BMO/web/js/form_validate.js',
+ 'js/attachment.js', 'js/field.js', 'js/util.js' ]
+ onload = "showCompDesc(document.getElementById('component'));"
+%]
+
+<h2>Finance</h2>
+
+<p>All fields are mandatory</p>
+
+<form method="post" action="post_bug.cgi" id="bug_form" class="enter_bug_form"
+ enctype="multipart/form-data" onsubmit="return onSubmit();">
+<input type="hidden" name="format" value="finance">
+<input type="hidden" name="product" value="Finance">
+<input type="hidden" name="rep_platform" value="All">
+<input type="hidden" name="op_sys" value="Other">
+<input type="hidden" name="priority" value="--">
+<input type="hidden" name="version" value="unspecified">
+<input type="hidden" name="bug_severity" id="bug_severity" value="normal">
+<input type="hidden" name="comment" id="comment" value="">
+<input type="hidden" name="groups" id="groups" value="finance">
+<input type="hidden" name="token" value="[% token FILTER html %]">
+
+<table>
+
+<tr>
+ <th>
+ <label for="component">Request Type:</label>
+ </th>
+ <td>
+ <select name="component" id="component" onchange="showCompDesc(this);">
+ [%- FOREACH c = product.components %]
+ [% NEXT IF NOT c.is_active %]
+ <option value="[% c.name FILTER html %]"
+ id="v[% c.id FILTER html %]_component"
+ [% IF c.name == default.component_ %]
+ selected="selected"
+ [% END %]>
+ [% c.name FILTER html -%]
+ </option>
+ [%- END %]
+ </select
+ </td>
+</tr>
+
+<tr>
+ <td></td>
+ <td id="comp_description" align="left" style="color: green; padding-left: 1em"></td>
+</tr>
+
+<tr>
+ <th>
+ <label for="short_desc">Description:</label>
+ </th>
+ <td>
+ <i>Short description of what is being asked to sign</i><br>
+ <input name="short_desc" id="short_desc" size="60"
+ value="[% short_desc FILTER html %]">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ <label for="team_priority">Priority to your Team:</label>
+ </th>
+ <td>
+ <select id="team_priority" name="team_priority">
+ <option value="Low">Low</option>
+ <option value="Medium">Medium</option>
+ <option value="High">High</option>
+ </select>
+ </td>
+</tr>
+
+<tr>
+ <th>
+ <label for="signature_time">Timeframe for Signature:</label>
+ </th>
+ <td>
+ <select id="signature_time" name="signature_time">
+ <option value="24 hours">Within 24 hours</option>
+ <option value="2 days">2 days</option>
+ <option value="A week">A week</option>
+ <option value="2 - 4 weeks" selected>2 -4 weeks</option>
+ </select>
+ </td>
+</tr>
+
+<tr>
+ <th>
+ <label for="other_party">Name of Other Party:</label>
+ </th>
+ <td>
+ <i>Include full legal entity name and any other relevant contact information</i><br>
+ <textarea id="other_party" name="other_party"
+ rows="5" cols="40"></textarea>
+ </td>
+<tr>
+
+<tr>
+ <th>
+ <label for="business_obj">Business Objective:</label>
+ </th>
+ <td>
+ <i>
+ Which Initiative or Overall goal this purchase is for. i.e. B2G, Data Center, Network, etc.</i><br>
+ <textarea id="business_obj" name="business_obj" rows="5" cols="40"></textarea>
+ </td>
+<tr>
+
+<tr>
+ <th>
+ <label for="what_purchase">If this is a purchase order,<br>what are we purchasing?</label>
+ </th>
+ <td>
+ <i>
+ Describe your request, what items are we purchasing, including number of
+ units if available.<br>Also provide context and background. Enter No if not
+ a purchase order.</i><br>
+ <textarea name="what_purchase" id="what_purchase" rows="5" cols="40"></textarea>
+ </td>
+</tr>
+
+<tr>
+ <th>
+ <label for="why_purchase">Why is this purchase needed?</label>
+ </th>
+ <td>
+ <i>
+ Why do we need this? What is the work around if this is not approved?</i><br>
+ <textarea name="why_purchase" id="why_purchase" rows="5" cols="40"></textarea>
+ </td>
+</tr>
+
+<tr>
+ <th>
+ <label for="risk_purchase">What is the risk if<br>this is not purchased?</label>
+ </th>
+ <td>
+ <i>
+ What will happen if this is not purchased?</i><br>
+ <textarea name="risk_purchase" id="risk_purchase" rows="5" cols="40"></textarea>
+ </td>
+</tr>
+
+<tr>
+ <th>
+ <label for="alternative_purchase">What is the alternative?</label>
+ </th>
+ <td>
+ <i>
+ How did the team come to this recommendation? Did we get other bids, if so, how many?</i><br>
+ <textarea name="alternative_purchase" id="alternative_purchase" rows="5" cols="40"></textarea>
+ </td>
+</tr>
+
+<tr>
+ <th>
+ <label for="total_cost">Total Cost</label>
+ </th>
+ <td>
+ <input type="text" name="total_cost" id="total_cost" value="" size="60">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ <label for="attachment">Attachment:</label>
+ </th>
+ <td>
+ <i>Upload document that needs to be signed. If this is a Purchase Request form,<br>
+ also upload any supporting document such as draft SOW, quote, order form, etc.</i>
+ <div>
+ <input type="file" id="attachment" name="data" size="50">
+ <input type="hidden" name="contenttypemethod" value="autodetect">
+ <input type="hidden" name="description" value="Finance Document">
+ </div>
+ </td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+ <td>
+ <input type="submit" id="commit" value="Submit Request">
+ </td>
+</tr>
+</table>
+
+</form>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-fxos-betaprogram.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-fxos-betaprogram.html.tmpl
new file mode 100644
index 000000000..3f8bbdd71
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-fxos-betaprogram.html.tmpl
@@ -0,0 +1,180 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% phones = [
+ 'ZTE Open',
+ 'Alcatel One Touch',
+ 'LG'
+] %]
+
+[% inline_css = BLOCK %]
+ #dogfood {
+ margin: 0 5em 0 2em;
+ }
+ #dogfood th {
+ text-align: left;
+ padding-top: 1em;
+ }
+[% END %]
+
+[% inline_js = BLOCK %]
+ function onSubmit() {
+ var alert_text = '';
+
+ var phone = false;
+ [% FOREACH phone = phones %]
+ if (document.getElementById('phone-cb-[% phone FILTER js %]').checked)
+ phone = true;
+ [% END %]
+ if (document.getElementById('phone-cb-other').checked && isFilledOut('phone-other'))
+ phone = true;
+ if (!phone)
+ alert_text += "Please select the type of phone you have.\n";
+
+ if (!isFilledOut('fxos-version'))
+ alert_text += "Please provide the version of Firefox OS you are running.\n";
+
+ if (!isFilledOut('short_desc'))
+ alert_text += "Please enter a value for the summary.\n";
+
+ if (!isFilledOut('details'))
+ alert_text += "Please describe your issue in more detail.\n";
+
+ if (alert_text != '') {
+ alert(alert_text);
+ return false;
+ }
+ return true;
+ }
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Firefox OS Beta Program $terms.Bug Submission"
+ style = inline_css
+ style_urls = [ 'skins/standard/enter_bug.css' ]
+ javascript = inline_js
+ javascript_urls = [ 'extensions/BMO/web/js/form_validate.js', 'js/field.js', 'js/util.js' ]
+%]
+
+<h2>Firefox OS Beta Program [% terms.Bug %] Submission</h2>
+
+<div id="public_place">
+ As [% terms.Bugzilla %] is a public place, don't include any private or
+ personally identifying content.
+</div>
+
+<form method="post" action="post_bug.cgi" id="bug_form" class="enter_bug_form"
+ enctype="multipart/form-data" onsubmit="return onSubmit();">
+<input type="hidden" name="format" value="fxos-betaprogram">
+<input type="hidden" name="created-format" value="fxos-betaprogram">
+<input type="hidden" name="product" value="Firefox OS">
+<input type="hidden" name="component" value="BetaTriage">
+<input type="hidden" name="rep_platform" value="ARM">
+<input type="hidden" name="op_sys" value="Gonk (Firefox OS)">
+<input type="hidden" name="priority" value="--">
+<input type="hidden" name="version" value="unspecified">
+<input type="hidden" name="bug_severity" id="bug_severity" value="normal">
+<input type="hidden" name="comment" id="comment" value="">
+<input type="hidden" name="status_whiteboard" id="status_whiteboard" value="[dogfood]">
+<input type="hidden" name="token" value="[% token FILTER html %]">
+
+<table id="dogfood">
+
+<tr>
+ <th>
+ What phone do you have?
+ </th>
+</tr>
+<tr>
+ <td>
+ [% FOREACH phone = phones %]
+ <input type="radio" name="phone" id="phone-cb-[% phone FILTER html %]"
+ value="[% phone FILTER html %]">
+ <label for="phone-cb-[% phone FILTER html %]">[% phone FILTER html %]</label><br>
+ [% END %]
+ <input type="radio" name="phone" id="phone-cb-other" value="Other">
+ <input type="text" name="phone_other" id="phone-other" placeholder="Other" size="20"
+ onfocus="document.getElementById('phone-cb-other').checked = true">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ What version of Firefox OS are you running?
+ </th>
+</tr>
+<tr>
+ <td>
+ <i>
+ Please check settings &gt; device information &gt; more information > OS version<br>
+ </i>
+ <input type="text" name="fxos_version" id="fxos-version" size="20">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ Please summarize your issue in one sentence:
+ </th>
+</tr>
+<tr>
+ <td>
+ <input type="text" name="short_desc" id="short_desc" size="60">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ Please describe your issue in more detail. If you have steps to
+ reproduce the problem, please include them here:
+ </th>
+</tr>
+<tr>
+ <td>
+ <textarea id="details" name="details" rows="5" cols="60"></textarea>
+ </td>
+</tr>
+
+<tr>
+ <th>
+ If your issue is associated with a specific app, which one
+ </th>
+</tr>
+<tr>
+ <td>
+ <input type="text" name="app" id="app" size="60">
+ </td>
+</tr>
+
+<tr>
+ <th>Security:</th>
+</tr>
+<tr>
+ <td>
+ <input type="checkbox" name="groups" id="default_security_group"
+ value="[% product.default_security_group FILTER html %]">
+ <label for="default_security_group">
+ Many users could be harmed by this security problem:
+ it should be kept hidden from the public until it is resolved.
+ </label>
+ </td>
+</tr>
+
+<tr>
+ <td>
+ <input type="submit" id="commit" value="Submit Request">
+ </td>
+</tr>
+
+</table>
+
+</form>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-fxos-feature.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-fxos-feature.html.tmpl
new file mode 100644
index 000000000..faa0495a4
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-fxos-feature.html.tmpl
@@ -0,0 +1,181 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% inline_style = BLOCK %]
+#feature_form {
+ padding: 10px;
+}
+#feature_form .required:after {
+ content: " *";
+ color: red;
+}
+#feature_form .field_label {
+ font-weight: bold;
+}
+#feature_form .field_desc {
+ padding-bottom: 3px;
+}
+#feature_form .field_desc,
+#feature_form .head_desc {
+ width: 600px;
+ word-wrap: normal;
+}
+#feature_form .head_desc {
+ padding-top: 5px;
+ padding-bottom: 12px;
+}
+#feature_form .form_section {
+ margin-bottom: 10px;
+}
+#feature_form textarea {
+ font-family: inherit;
+ font-size: inherit;
+}
+#feature_form #comp_description {
+ test-align: left;
+ color: green;
+ padding-left: 1em;
+}
+[% END %]
+
+[% inline_javascript = BLOCK %]
+var compdesc = new Array();
+compdesc[""] = 'Please select a component from the list above.';
+[% FOREACH comp = product.components %]
+ compdesc['[% comp.name FILTER js %]'] = '[% comp.description FILTER js %]';
+[% END %]
+function showCompDesc() {
+ var comp_select = document.getElementById('component');
+ document.getElementById('comp_description').innerHTML = compdesc[comp_select.value];
+}
+function validateAndSubmit() {
+ var alert_text = '';
+ if (!isFilledOut('component')) alert_text += 'Please select a value for product component.\n';
+ if (!isFilledOut('short_desc')) alert_text += 'Please enter a value for feature request title.\n';
+ if (alert_text != '') {
+ alert(alert_text);
+ return false;
+ }
+ return true;
+}
+YAHOO.util.Event.onDOMReady(showCompDesc);
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Firefox OS Feature Request Form"
+ style = inline_style
+ javascript = inline_javascript
+ javascript_urls = [ 'extensions/BMO/web/js/form_validate.js' ]
+%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+
+<form id="feature_form" method="post" action="post_bug.cgi" enctype="multipart/form-data"
+ onSubmit="return validateAndSubmit();">
+ <input type="hidden" name="format" value="fxos-feature">
+ <input type="hidden" name="product" value="Firefox OS">
+ <input type="hidden" name="keywords" value="feature">
+ <input type="hidden" name="rep_platform" value="All">
+ <input type="hidden" name="op_sys" value="Other">
+ <input type="hidden" name="version" value="unspecified">
+ <input type="hidden" name="bug_severity" id="bug_severity" value="normal">
+ <input type="hidden" name="token" value="[% token FILTER html %]">
+
+<img title="Firefox OS Feature Form" src="extensions/BMO/web/producticons/firefox.png">
+
+<div class="form_section">
+ <label for="component" class="field_label required">Product Component</label>
+ <div class="field_desc">
+ Which product component is your feature request applicable to?
+ If you are not sure, choose "General".
+ </div>
+ <select name="component" id="component" onchange="showCompDesc(this);">
+ <option value="">Select One</option>
+ [%- FOREACH c = product.components %]
+ [% NEXT IF NOT c.is_active %]
+ <option value="[% c.name FILTER html %]"
+ id="v[% c.id FILTER html %]_component"
+ [% IF c.name == default.component_ %]
+ selected="selected"
+ [% END %]>
+ [% c.name FILTER html -%]
+ </option>
+ [%- END %]
+ </select>
+ <div id="comp_description"></div>
+</div>
+
+<div class="form_section">
+ <label for="short_desc" class="field_label required">Feature Request Title</label>
+ <div class="field_desc">
+ Please enter a title for your feature request that is brief and self explanatory.
+ (Example: "Memory dialing using keypad numbers")
+ </div>
+ <input type="text" name="short_desc" id="short_desc" size="80">
+</div>
+
+<div class="form_section">
+ <label for="description" class="field_label">Description of feature or problem to be solved</label>
+ <div class="field_desc">
+ Please describe the feature that you are requesting or the problem that you would like solved in detail
+ (Example, "Today, there is no way for the user to quickly dial user-defined numbers from the dial pad.
+ Instead the user must search for an find the contact in their contact list.").
+ If the described feature only applies to certain device types (eg. tablet vs. smartphone), please make note of it.
+ </div>
+ <textarea id="description" name="description" cols="80" rows="5"></textarea>
+</div>
+
+<div class="form_section">
+ <label for="implement_impact" class="field_label">Impact of implementing the feature/solution</label>
+ <div class="field_desc">
+ If this solution were to be implemented, what would the impact be?
+ (Example, "If this solution were to be implemented, it would save the users
+ significant time when dialing commonly used phone numbers.")
+ </div>
+ <textarea id="implement_impact" name="implement_impact" cols="80" rows="5"></textarea>
+</div>
+
+<div class="form_section">
+ <label for="not_implement_impact" class="field_label">Impact of NOT implementing the feature/solution</label>
+ <div class="field_desc">
+ If this solution were NOT to be implemented, what would the impact be?
+ (Example, "By not implementing this solution, we are unable to sell phones in
+ Iceland which has a certification requirement to have support for memory dialing.")
+ </div>
+ <textarea id="not_implement_impact" name="not_implement_impact" cols="80" rows="5"></textarea>
+</div>
+
+<div class="form_section">
+ <label for="date_required" class="field_label">Date required</label>
+ <div class="field_desc">
+ Is this solution required by a certain date? Why?
+ (Example: "March 2014. We plan to sell phones in Iceland in June 2014 using Firefox OS 1.4.
+ Completing the feature in March would allow the device to pass operator certification in time
+ for a June retail launch.")<br>
+ <strong>Note:</strong> completing this field does not imply that the feature will indeed be delivered in this timeframe.
+ </div>
+ <textarea id="date_required" name="date_required" cols="80" rows="5"></textarea>
+</div>
+
+<div class="head_desc">
+ Once your form has been submitted, a tracking [% terms.bug %] will be created. We will
+ then reach out for additional info and next steps. Thanks!
+</div>
+
+<input type="submit" id="commit" value="Submit">
+
+<p>
+ [ <span class="required_star">*</span> <span class="required_explanation">Required Field</span> ]
+</p>
+
+</form>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-fxos-mcts-waiver.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-fxos-mcts-waiver.html.tmpl
new file mode 100644
index 000000000..bfd624a8a
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-fxos-mcts-waiver.html.tmpl
@@ -0,0 +1,208 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% inline_style = BLOCK %]
+#fxos_mcts_waiver_form {
+ padding: 10px;
+}
+#fxos_mcts_waiver_form .required:after {
+ content: " *";
+ color: red;
+}
+#fxos_mcts_waiver_form .field_label {
+ font-weight: bold;
+}
+#fxos_mcts_waiver_form .field_desc {
+ padding-bottom: 3px;
+}
+#fxos_mcts_waiver_form .field_desc,
+#fxos_mcts_waiver_form .head_desc {
+ width: 600px;
+ word-wrap: normal;
+}
+#fxos_mcts_waiver_form .head_desc {
+ padding-top: 5px;
+ padding-bottom: 12px;
+}
+#fxos_mcts_waiver_form .form_section {
+ margin-bottom: 10px;
+}
+#fxos_mcts_waiver_form textarea {
+ font-family: inherit;
+ font-size: inherit;
+}
+#fxos_mcts_waiver_form em {
+ font-size: 1em;
+}
+[% END %]
+
+[% inline_javascript = BLOCK %]
+function validateAndSubmit() {
+ 'use strict';
+ var alert_text = '';
+ var requiredLabels = YAHOO.util.Selector.query('label.required');
+ if (requiredLabels) {
+ requiredLabels.forEach(function (label) {
+ var name = label.getAttribute('for');
+ var ids = YAHOO.util.Selector.query(
+ '#fxos_mcts_waiver_form *[name="' + name + '"]'
+ ).map(function (e) {
+ return e.id
+ });
+
+ if (ids && ids[0]) {
+ if (!isFilledOut(ids[0])) {
+ var desc = label.textContent || name;
+ alert_text +=
+ "Please enter a value for " +
+ desc.replace(/[\r\n]+/, "").replace(/\s+/g, " ") +
+ "\n";
+ }
+ }
+ });
+ }
+
+ if (alert_text != '') {
+ alert(alert_text);
+ return false;
+ }
+
+ var short_desc = document.getElementById('short_desc');
+ var company_name = document.getElementById('company_name').value;
+ short_desc.value = "MCTS Waiver for " + company_name;
+
+ return true;
+}
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Firefox OS MCTS Waiver Form"
+ style = inline_style
+ javascript = inline_javascript
+ javascript_urls = [ 'extensions/BMO/web/js/form_validate.js',
+ 'js/field.js', 'js/util.js' ]
+ yui = [ 'selector' ]
+%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+
+<form id="fxos_mcts_waiver_form" method="post" action="post_bug.cgi"
+ enctype="multipart/form-data" onSubmit="return validateAndSubmit();">
+ <input type="hidden" name="format" value="fxos-mcts-waiver">
+ <input type="hidden" name="product" value="Firefox OS">
+ <input type="hidden" name="component" value="MCTS Waiver Request">
+ <input type="hidden" name="rep_platform" value="All">
+ <input type="hidden" name="op_sys" value="Other">
+ <input type="hidden" name="version" value="unspecified">
+ <input type="hidden" name="bug_severity" id="bug_severity" value="normal">
+ <input type="hidden" name="token" value="[% token FILTER html %]">
+ <input type="hidden" name="groups" value="mozilla-employee-confidential">
+ <input type="hidden" id="short_desc" name="short_desc" value="">
+ <input type="hidden" name="cf_user_story" value="Engineering Analysis:
+
+
+Technical Account Manager Recommendation:
+
+
+">
+
+ <div class="head_desc">
+ Welcome to the [% title FILTER html %]!
+ </div>
+
+ <div class="form_section">
+ <label for="company_name" class="field_label required">Company Name</label>
+ <div class="field_desc">
+ Please enter the legal name of the company requesting the Waiver
+ </div>
+ <input type="text" name="company_name" id="company_name" size="80">
+ </div>
+
+ <div class="form_section">
+ <label for="device_desc" class="field_label required">Device Description</label>
+ <div class="field_desc">
+ Please enter the Make, Model, Chipset, screensize and type the device associated with the waiver request. For
+ example type may be mobile phone, tablet, dongle, tv, etc.
+ </div>
+ <textarea id="device_desc" name="device_desc" cols="80" rows="5"></textarea>
+ </div>
+
+ <div class="form_section">
+ <label for="ffos_release" class="field_label required">FFOS Release</label>
+ <div class="field_desc">
+ Please Enter the Release this Waiver applies to for this partner.
+ </div>
+ <input type="text" name="ffos_release" id="ffos_release" size="80">
+ </div>
+
+ <div class="form_section">
+ <label for="branding_tier" class="field_label required">Branding Tier</label>
+ <div class="field_desc">
+ Please Enter the Branding Tier associated with the Waiver Request (Powered by Firefox OS or Co-Branded).
+ </div>
+ <select name="branding_tier" id="branding_tier">
+ <option value="Firefox OS Inside">Firefox OS Inside</option>
+ <option value="Powered by Firefox OS">Powered by Firefox OS</option>
+ <option value="Firefox OS Co-branded">Firefox OS Co-branded</option>
+ </select>
+ </div>
+
+ <div class="form_section">
+ <label for="dist_countries" class="field_label required">Distribution Countries</label>
+ <div class="field_desc">
+ Please include list of countries where the device is planned to be distributed.
+ </div>
+ <textarea id="dist_countries" name="dist_countries" cols="80" rows="5"></textarea>
+ </div>
+
+ <div class="form_section">
+ <label for="dist_channel" class="field_label required">Distribution Channel</label>
+ <div class="field_desc">
+ Please identify how this device will be sold. For example, Operator, Retail.
+ </div>
+ <input type="text" name="dist_channel" id="dist_channel" size="80">
+ </div>
+
+ <div class="form_section">
+ <label for="reason" class="field_label required">Reason for Waiver Request</label>
+ <div class="field_desc">
+ Please describe which test cases, Branding Guidelines and/or Requirements the Partner is request waived.
+ </div>
+ <textarea id="reason" name="reason" cols="80" rows="5"></textarea>
+ </div>
+
+ <div class="form_section">
+ <label for="rationale" class="field_label required">Rationale for Granting Waiver Request</label>
+ <div class="field_desc">
+ Please document why the Partner thinks a waiver should be granted.
+ </div>
+ <textarea id="rationale" name="rationale" cols="80" rows="5"></textarea>
+ </div>
+
+ <div class="form_section">
+ <label for="impact" class="field_label required">Impact Analysis</label>
+ <div class="field_desc">
+ Please provide an assessment of the impact of granting this waiver in general business terms (this should include
+ broad perspective of potential issues such as brand consistency, impacts on reporting &amp; tracking capabilities,
+ help desk/support issues, etc.)
+ </div>
+ <textarea id="impact" name="impact" cols="80" rows="5"></textarea>
+ </div>
+
+ <input type="submit" id="commit" value="Submit">
+
+ <p>
+ [ <span class="required_star">*</span> <span class="required_explanation">
+ Required Field</span> ]
+ </p>
+</form>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-fxos-partner.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-fxos-partner.html.tmpl
new file mode 100644
index 000000000..3e910990d
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-fxos-partner.html.tmpl
@@ -0,0 +1,239 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% inline_js = BLOCK %]
+ var compdesc = new Array();
+ compdesc[""] = 'Please select a component from the list above.';
+ [% FOREACH comp = product.components %]
+ compdesc['[% comp.name FILTER js %]'] = '[% comp.description FILTER js %]';
+ [% END %]
+ function showCompDesc(component) {
+ var value = component.value;
+ document.getElementById('comp_description').innerHTML = compdesc[value];
+ }
+ function onSubmit() {
+ var alert_text = '';
+ var status_whiteboard = '';
+
+ if (!isFilledOut('component'))
+ alert_text += "Please select a value for component.\n";
+ if (!isFilledOut('short_desc'))
+ alert_text += "Please enter a value for the summary.\n";
+ if (!isFilledOut('steps_to_reproduce'))
+ alert_text += "Please enter the steps to reproduce.\n";
+ if (!isFilledOut('actual_behavior'))
+ alert_text += "Please enter the actual behavior.\n";
+ if (!isFilledOut('expected_behavior'))
+ alert_text += "Please enter the expected behavior.\n";
+ if (!isFilledOut('build'))
+ alert_text += "Please enter a value for the build.\n";
+ if (!isFilledOut('requirements'))
+ alert_text += "Please enter a value for the requirements.\n";
+
+ var device_values = new Array();
+ var device_select = document.getElementById("b2g_device");
+ for (var i = 0, l = device_select.options.length; i < l; i++) {
+ if (device_select.options[i].selected)
+ device_values.push(device_select.options[i].value);
+ }
+
+ if (device_values.length == 0)
+ alert_text += "Please select one or more devices.\n";
+
+ if (alert_text != '') {
+ alert(alert_text);
+ return false;
+ }
+
+ for (var i = 0, l = device_values.length; i < l; i++)
+ status_whiteboard += '[device:' + device_values[i] + '] ';
+
+ if (document.getElementById('third_party_app').checked)
+ status_whiteboard += '[apps watch list]';
+
+ document.getElementById('status_whiteboard').value = status_whiteboard;
+
+ return true;
+ }
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Firefox OS Partner $terms.Bug Submission"
+ style_urls = [ 'skins/standard/enter_bug.css' ]
+ javascript = inline_js
+ javascript_urls = [ 'extensions/BMO/web/js/form_validate.js',
+ 'js/attachment.js', 'js/field.js', 'js/util.js' ]
+ onload = "showCompDesc(document.getElementById('component'));"
+%]
+
+<h2>Firefox OS Partner [% terms.Bug %] Submission</h2>
+
+<p>All fields are mandatory</p>
+
+<form method="post" action="post_bug.cgi" id="bug_form" class="enter_bug_form"
+ enctype="multipart/form-data" onsubmit="return onSubmit();">
+<input type="hidden" name="format" value="fxos-partner">
+<input type="hidden" name="product" value="Firefox OS">
+<input type="hidden" name="rep_platform" value="ARM">
+<input type="hidden" name="op_sys" value="Gonk (Firefox OS)">
+<input type="hidden" name="priority" value="--">
+<input type="hidden" name="version" value="unspecified">
+<input type="hidden" name="bug_severity" id="bug_severity" value="normal">
+<input type="hidden" name="comment" id="comment" value="">
+<input type="hidden" name="keywords" id="keywords" value="unagi">
+<input type="hidden" name="status_whiteboard" id="status_whiteboard" value="">
+<input type="hidden" name="token" value="[% token FILTER html %]">
+
+<table>
+
+<tr>
+ <th>
+ <label for="short_desc">Summary:</label>
+ </th>
+ <td>
+ <input name="short_desc" id="short_desc" size="60"
+ value="[% short_desc FILTER html %]">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ <label for="component">Component:</label>
+ </th>
+ <td>
+ <select name="component" id="component" onchange="showCompDesc(this);">
+ <option value="">Select One</option>
+ [%- FOREACH c = product.components %]
+ [% NEXT IF NOT c.is_active %]
+ <option value="[% c.name FILTER html %]"
+ id="v[% c.id FILTER html %]_component"
+ [% IF c.name == default.component_ %]
+ selected="selected"
+ [% END %]>
+ [% c.name FILTER html -%]
+ </option>
+ [%- END %]
+ </select
+ </td>
+</tr>
+
+<tr>
+ <td></td>
+ <td id="comp_description" align="left" style="color: green; padding-left: 1em"></td>
+</tr>
+
+<tr>
+ <th>
+ <label for="b2g_device">B2G Device:</label>
+ </th>
+ <td>
+ <select name="b2g_device" id="b2g_device"
+ size="5" multiple="multiple">
+ <option name="Otoro">Otoro</option>
+ <option name="Unagi">Unagi</option>
+ <option name="Inari">Inari</option>
+ <option name="Ikura">Ikura</option>
+ <option name="Hamachi">Hamachi</option>
+ <option name="Buri">Buri</option>
+ <option name="Toro">Toro</option>
+ <option name="Leo">Leo</option>
+ <option name="Twist">Twist</option>
+ <option name="Zero">Zero</option>
+ <option name="Tara">Tara</option>
+ </select>
+ </td>
+</tr>
+
+<tr>
+ <th>
+ <label for="other_party">What are the steps to reproduce?:</label>
+ </th>
+ <td>
+ <textarea id="steps_to_reproduce" name="steps_to_reproduce" rows="5" cols="60">1.
+2.
+3.</textarea>
+ </td>
+<tr>
+
+<tr>
+ <th>
+ <label for="actual_behavior">What was the actual behavior?:</label>
+ </th>
+ <td>
+ <textarea id="actual_behavior" name="actual_behavior" rows="5" cols="60"></textarea>
+ </td>
+<tr>
+
+<tr>
+ <th>
+ <label for="expected_behavior">What was the expected behavior?:</label>
+ </th>
+ <td>
+ <textarea name="expected_behavior" id="expected_behavior" rows="5" cols="60"></textarea>
+ </td>
+</tr>
+
+<tr>
+ <th>
+ <label for="build">What build were you using?:</label>
+ </th>
+ <td>
+ <input type="text" name="build" id="build" value="" size="60">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ <label for="requirements">What are the requirements?:</label>
+ </th>
+ <td>
+ <input type="text" name="requirements" id="requirements" value="" size="60">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ <label for="requirements">Third party app content?:</label>
+ </th>
+ <td>
+ <input type="checkbox" name="third_party_app" id="third_party_app">
+ </td>
+</tr>
+
+<tr>
+ <th>Security:</th>
+ <td>
+ <input type="checkbox" name="groups" id="default_security_group"
+ value="[% product.default_security_group FILTER html %]"
+ [% FOREACH g = group %]
+ [% IF g.name == name %]
+ [% ' checked="checked"' IF g.checked %]
+ [% LAST %]
+ [% END %]
+ [% END %]
+ >
+ <label for="default_security_group">
+ Many users could be harmed by this security problem:
+ it should be kept hidden from the public until it is resolved.
+ </label>
+ </td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+ <td>
+ <input type="submit" id="commit" value="Submit Request">
+ </td>
+</tr>
+</table>
+
+</form>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-fxos-preload-app.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-fxos-preload-app.html.tmpl
new file mode 100644
index 000000000..edf7fdbae
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-fxos-preload-app.html.tmpl
@@ -0,0 +1,185 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% inline_style = BLOCK %]
+#fxos_preload_app_form {
+ padding: 10px;
+}
+#fxos_preload_app_form .required:after {
+ content: " *";
+ color: red;
+}
+#fxos_preload_app_form .field_label {
+ font-weight: bold;
+}
+#fxos_preload_app_form .field_desc {
+ padding-bottom: 3px;
+}
+#fxos_preload_app_form .field_desc,
+#fxos_preload_app_form .head_desc {
+ width: 600px;
+ word-wrap: normal;
+}
+#fxos_preload_app_form .head_desc {
+ padding-top: 5px;
+ padding-bottom: 12px;
+}
+#fxos_preload_app_form .form_section {
+ margin-bottom: 10px;
+}
+#fxos_preload_app_form textarea {
+ font-family: inherit;
+ font-size: inherit;
+}
+#fxos_preload_app_form em {
+ font-size: 1em;
+}
+.yui-calcontainer {
+ z-index: 2;
+}
+[% END %]
+
+[% inline_javascript = BLOCK %]
+function validateAndSubmit() {
+ 'use strict';
+ var alert_text = '';
+ var requiredLabels = YAHOO.util.Selector.query('label.required');
+ if (requiredLabels) {
+ requiredLabels.forEach(function (label) {
+ var name = label.getAttribute('for');
+ var ids = YAHOO.util.Selector.query(
+ '#fxos_preload_app_form *[name="' + name + '"]'
+ ).map(function (e) {
+ return e.id
+ });
+
+ if (ids && ids[0]) {
+ if (!isFilledOut(ids[0])) {
+ var desc = label.textContent || name;
+ alert_text +=
+ "Please enter a value for " +
+ desc.replace(/[\r\n]+/, "").replace(/\s+/g, " ") +
+ "\n";
+ }
+ }
+ });
+ }
+
+ if (alert_text != '') {
+ alert(alert_text);
+ return false;
+ }
+ return true;
+}
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Firefox OS Pre-load App"
+ style = inline_style
+ javascript = inline_javascript
+ javascript_urls = [ 'extensions/BMO/web/js/form_validate.js',
+ 'js/field.js', 'js/util.js' ]
+ yui = [ "autocomplete", "calendar", "selector" ]
+%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+
+<form id="fxos_preload_app_form" method="post" action="post_bug.cgi"
+ enctype="multipart/form-data" onSubmit="return validateAndSubmit();">
+ <input type="hidden" name="format" value="fxos-preload-app">
+ <input type="hidden" name="product" value="Marketplace">
+ <input type="hidden" name="component" value="Pre-Installed Apps">
+ <input type="hidden" name="rep_platform" value="All">
+ <input type="hidden" name="op_sys" value="Other">
+ <input type="hidden" name="version" value="1.0">
+ <input type="hidden" name="bug_severity" id="bug_severity" value="normal">
+ <input type="hidden" name="token" value="[% token FILTER html %]">
+ <input type="hidden" name="short_desc" value="Information Request: Pre-Installed Apps">
+ <input type="hidden" name="groups" value="mozilla-employee-confidential">
+
+ <div class="head_desc">
+ Welcome to the Firefox OS Pre-load App Info Request Form!
+ </div>
+
+ <div class="form_section">
+ <label for="company_name" class="field_label required">Company Name</label>
+ <div class="field_desc">
+ Please enter the legal name of your company
+ </div>
+ <input type="text" name="company_name" id="company_name" size="80">
+ </div>
+
+
+ <div class="form_section">
+ <label for="apps_business_dev_contact_name" class="field_label required">Apps Business Development Contact Name</label>
+ <div class="field_desc">Please enter your Name</div>
+ <input type="text" name="apps_business_dev_contact_name" id="apps_business_dev_contact_name" size="80">
+ </div>
+
+ <div class="form_section">
+ <label for="apps_business_dev_contact_email" class="field_label required">Apps Business Development Contact Email</label>
+ <div class="field_desc">Please enter your Email address.</div>
+ <input type="text" name="apps_business_dev_contact_email" id="apps_business_dev_contact_email"
+ value="[% user.email FILTER html %]" size="80">
+ </div>
+
+ <div class="form_section">
+ <label for="preload_apps" class="field_label required">Name of Firefox Marketplace apps of interest to you:</label>
+ <div class="field_desc">
+ Please provide the App Name and Marketplace URL for each app you wish to pre-load on your certified, branded
+ Firefox OS device. The Marketplace URL is an important identifier because there are many apps in Marketplace with
+ the same name.
+ </div>
+ <textarea id="preload_apps" name="preload_apps"
+ cols="80" rows="5"></textarea>
+ </div>
+
+ <div class="form_section">
+ <label for="countries" class="field_label required">Countries where your device will be distributed</label>
+ <div class="field_desc">
+ Please list the countries where your device will be distributed. This information is required because it
+ corresponds to the countries that the developers will evaluate for distribution rights.
+ </div>
+ <textarea id="countries" name="countries"
+ cols="80" rows="5"></textarea>
+ </div>
+
+ <div class="form_section">
+ <label for="release_info" class="field_label required">Release Information</label>
+ <div class="field_desc">
+ Please provide the Version of Firefox OS for your Branded, Certified device on which you plan to pre-load the
+ requested apps.
+ </div>
+ <input type="text" name="release_info" id="release_info" size="80">
+ </div>
+
+ <div class="form_section">
+ <label for="device_info" class="field_label required">Device Information</label>
+ <div class="field_desc">
+ Please include the device make and model, screen size, Chipset and RAM configuration for the Branded, Certified
+ device on which you plan to pre-load the requested apps.
+ </div>
+ <textarea id="device_info" name="device_info"
+ cols="80" rows="5"></textarea>
+ </div>
+
+ <p>When you press submit the information you've provided will be routed to Mozilla team members for follow up. The
+ system will also respond with a [% terms.Bugzilla %] tracking number that you may use for follow up.</p>
+
+ <input type="submit" id="commit" value="Submit">
+
+ <p>
+ [ <span class="required_star">*</span> <span class="required_explanation">
+ Required Field</span> ]
+ </p>
+</form>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-ipp.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-ipp.html.tmpl
new file mode 100644
index 000000000..fb59cfeb3
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-ipp.html.tmpl
@@ -0,0 +1,183 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% inline_style = BLOCK %]
+#ipp_form th {
+ text-align: right;
+}
+
+#ipp_form input[type="text"], #ipp_form textarea {
+ width: 100%;
+}
+
+#ipp_form textarea {
+ font-family: inherit;
+ font-size: inherit;
+}
+
+#standard_link {
+ margin-top: 2em;
+}
+
+#standard_link img {
+ vertical-align: middle;
+}
+
+#standard_link a {
+ cursor: pointer;
+}
+
+[% END %]
+
+[% inline_javascript = BLOCK %]
+function validateAndSubmit() {
+ var alert_text = '';
+ if (!isFilledOut('component')) alert_text += 'Please select the "Area".\n';
+ if (!isFilledOut('short_desc')) alert_text += 'Please enter a "Summary".\n';
+ if (!isFilledOut('region')) alert_text += 'Please enter the "Region/Country".\n';
+ if (!isFilledOut('desc')) alert_text += 'Please provide a "Description".\n';
+ if (!isFilledOut('relevance')) alert_text += 'Please provide some "Relevance".\n';
+ if (!isFilledOut('goal')) alert_text += 'Please enter the "Goal".\n';
+ if (!isFilledOut('when')) alert_text += 'Please enter data for the "When" field.\n';
+ if (alert_text != '') {
+ alert(alert_text);
+ return false;
+ }
+ return true;
+}
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Internet Public Policy Issue"
+ style = inline_style
+ javascript = inline_javascript
+ javascript_urls = [ 'extensions/BMO/web/js/form_validate.js',
+ 'js/field.js', 'js/util.js', 'js/bug.js' ]
+%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+
+<h1>Internet Public Policy Issue</h1>
+
+<form method="post" action="post_bug.cgi" enctype="multipart/form-data"
+ onSubmit="return validateAndSubmit();">
+ <input type="hidden" name="format" value="ipp">
+ <input type="hidden" name="product" value="Internet Public Policy">
+ <input type="hidden" name="rep_platform" value="All">
+ <input type="hidden" name="op_sys" value="Other">
+ <input type="hidden" name="version" value="unspecified">
+ <input type="hidden" name="bug_severity" id="bug_severity" value="normal">
+ <input type="hidden" name="token" value="[% token FILTER html %]">
+
+<table id="ipp_form">
+
+<tr>
+ <th class="required">Area</th>
+ <td>
+ <select name="component" id="component">
+ <option value="">Please select..</option>
+ [% FOREACH component = product.components %]
+ <option value="[% component.name FILTER html %]">
+ [% component.name FILTER html %]
+ </option>
+ [% END %]
+ </select>
+ </td>
+</tr>
+
+<tr>
+ <th class="required">Summary</th>
+ <td>
+ <input type="text" name="short_desc" id="short_desc" size="60"
+ placeholder="(Describe issue in one sentence)">
+ </td>
+</tr>
+
+<tr>
+ <th class="required">Region/Country</th>
+ <td>
+ <input type="text" name="region" id="region" size="60">
+ </td>
+</tr>
+
+<tr>
+ <th class="required">Description</th>
+ <td>
+ <textarea id="desc" name="desc" cols="50" rows="5"
+ placeholder="(Explain the legislative or policy activity which is happening)"></textarea>
+ </td>
+</tr>
+
+<tr>
+ <th class="required">Relevance</th>
+ <td>
+ <textarea id="relevance" name="relevance" cols="50" rows="5"
+ placeholder="(Why should Mozilla care? What’s the impact on the open internet?)"></textarea>
+ </td>
+</tr>
+
+<tr>
+ <th class="required">Goal</th>
+ <td>
+ <input type="text" name="goal" id="goal" size="60"
+ placeholder="(What would success look like for Mozilla?)">
+ </td>
+</tr>
+
+<tr>
+ <th class="required">When</th>
+ <td>
+ <input type="text" name="when" id="when" size="60"
+ placeholder="(Describe the timeline or due date)">
+ </td>
+</tr>
+
+<tr>
+ <th class="required">Urgency</th>
+ <td>
+ <select name="priority" id="priority">
+ <option value="P1">Urgent</option>
+ <option value="P3">Needs Attention Soon</option>
+ <option value="P5" selected>When You Get To It</option>
+ </select>
+ </td>
+</tr>
+
+<tr>
+ <th>Additional Information</th>
+ <td>
+ <textarea id="additional" name="additional" cols="50" rows="5"
+ placeholder="(Please supply links to relevant articles/websites/organizations)"></textarea>
+ </td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+ <td><input type="submit" id="commit" value="Submit Issue"></td>
+</tr>
+
+</table>
+</form>
+
+[ <span class="required_star">*</span> <span class="required_explanation">Required Field</span> ]
+
+<div id="standard_link">
+ <a href="enter_bug.cgi?format=__standard__&product=[% product.name FILTER uri %]">
+ <img src="extensions/BMO/web/images/advanced.png" width="16" height="16" border="0"></a>
+ <a href="enter_bug.cgi?format=__standard__&product=[% product.name FILTER uri %]">
+ Switch to the standard [% terms.bug %] entry form</a>
+</div>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-itrequest.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-itrequest.html.tmpl
new file mode 100644
index 000000000..57c11a08a
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-itrequest.html.tmpl
@@ -0,0 +1,238 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% inline_javascript = BLOCK %]
+ function setsevdesc(theSelect) {
+ var theValue = theSelect.options[theSelect.selectedIndex].value;
+ if (theValue == 'blocker') {
+ document.getElementById('blockerdesc').style.display = 'block';
+ document.getElementById('critdesc').style.display = 'none';
+ } else if (theValue == 'critical') {
+ document.getElementById('blockerdesc').style.display = 'none';
+ document.getElementById('critdesc').style.display = 'block';
+ } else {
+ document.getElementById('blockerdesc').style.display = 'none';
+ document.getElementById('critdesc').style.display = 'none';
+ }
+ }
+
+ var compdesc = new Array();
+ [% FOREACH comp IN product.components %]
+ compdesc['[% comp.name FILTER js %]'] = '[% comp.description FILTER js %]';
+ [% END %]
+ compdesc['Server Operations'] = 'System administration for the mozilla.org servers. ' +
+ 'Requests for Server Ops that don\'t fit in any of the ' +
+ 'other Server Ops components can go here.';
+
+ var serviceNowText = 'Use <a href="https://mozilla.service-now.com/">Service Now</a> to:<br>' +
+ 'Request an LDAP/E-mail/etc. account<br>' +
+ 'Desktop/Laptop/Printer/Phone/Tablet/License problem/order/request';
+
+ function setcompdesc(theRadio) {
+ if (theRadio.id == 'component_service_desk') {
+ [%# helpdesk issue/request %]
+ document.getElementById('main_form').style.display = 'none';
+ document.getElementById('service_now_form').style.display = '';
+ document.getElementById('compdescription').innerHTML = serviceNowText;
+ } else {
+ document.getElementById('main_form').style.display = '';
+ document.getElementById('service_now_form').style.display = 'none';
+ var theValue = theRadio.value;
+ var compDescText = compdesc[theValue];
+ // If 'Server Operations', product must be changed to 'mozilla.org'
+ // otherwise set to 'Infrastructure & Operations'
+ if (theRadio.id == 'component_server_ops') {
+ compDescText = compDescText + '<br><br>' + serviceNowText;
+ document.getElementById('product').value = 'mozilla.org';
+ }
+ else {
+ document.getElementById('product').value = 'Infrastructure & Operations';
+ }
+ document.getElementById('compdescription').innerHTML = compDescText;
+ }
+ }
+
+ function on_submit() {
+ if (document.getElementById('componentsd').checked) {
+ [%# redirect desktop issues to service-now #%]
+ document.location.href = 'https://mozilla.service-now.com/';
+ return false;
+ }
+ return true;
+ }
+
+ YAHOO.util.Event.onDOMReady(function() {
+ var comps = document.getElementsByName('component');
+ for (var i = 0, l = comps.length; i < l; i++) {
+ if (comps[i].checked) {
+ setcompdesc(comps[i]);
+ break;
+ }
+ }
+ });
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Mozilla Corporation/Foundation IT Requests"
+ javascript = inline_javascript
+ javascript_urls = [ 'js/field.js' ]
+ yui = [ 'autocomplete' ]
+%]
+
+[% USE Bugzilla %]
+
+<p><strong>Please use this form for IT requests only!</strong></p>
+<p>If you have a [% terms.bug %] to file, go <a href="enter_bug.cgi">here</a>.</p>
+
+<form method="post" action="post_bug.cgi" id="itRequestForm" enctype="multipart/form-data"
+ onsubmit="return on_submit()">
+ <input type="hidden" id="product" name="product" value="Infrastructure & Operations">
+ <input type="hidden" name="rep_platform" value="All">
+ <input type="hidden" name="op_sys" value="Other">
+ <input type="hidden" name="priority" value="--">
+ <input type="hidden" name="version" value="other">
+ <input type="hidden" name="token" value="[% token FILTER html %]">
+ <table>
+ <tr>
+
+ <td align="right">
+ <strong>Urgency:</strong>
+ </td>
+
+ <td>
+ <select id="bug_severity" name="bug_severity" onchange="setsevdesc(this)">
+ <option value="blocker">All work for IT stops until this is done</option>
+ <option value="critical">IT should work on it soon as possible (urgent)</option>
+ <option value="major">IT should get to it within 24 hours</option>
+ <option value="normal">IT should get to it within the next week</option>
+ <option value="minor" selected="selected">No rush, but hopefully IT can get to it soon</option>
+ <option value="trivial">Whenever IT can get around to it</option>
+ <option value="enhancement">This is just an idea, filing it so we don't forget</option>
+ </select>
+ </td>
+ <td>
+ <div id="blockerdesc" style="color:red;display:none">This will page the on-call sysadmin if not handled within 30 minutes.</div>
+ <div id="critdesc" style="color:red;display:none">This will page the on-call sysadmin if not handled within 8 hours.</div>
+ </td>
+
+ </tr>
+ <tr>
+ <td align="right"><strong>Request Type:</strong></td>
+ <td style="white-space: nowrap;">
+ <input type="radio" name="component" id="component_service_desk" onclick="setcompdesc(this)" value="Desktop Issues">
+ <label for="component_service_desk">Service Desk issue/request</label><br>
+ <input type="radio" name="component" id="component_relops" onclick="setcompdesc(this)" value="RelOps">
+ <label for="component_relops">Report a problem with a tinderbox machine</label><br>
+ <input type="radio" name="component" id="component_webops_other" onclick="setcompdesc(this)" value="WebOps: Other">
+ <label for="component_webops_other">Report a problem with a Mozilla website, or to request a change or push</label><br>
+ <input type="radio" name="component" id="component_netops_acl" onclick="setcompdesc(this)" value="NetOps: DC Other">
+ <label for="component_netops_acl">Request a firewall change</label><br>
+ <input type="radio" name="component" id="component_server_ops" onclick="setcompdesc(this)" value="Server Operations">
+ <label for="component_server_ops">Any other issue</label><br>
+ Mailing list requests should be filed <a href="[% ulrbase FILTER none %]enter_bug.cgi?product=mozilla.org&amp;format=mozlist">here</a> instead.
+ </td>
+ <td id="compdescription" align="left" style="color: green; padding-left: 1em">
+ </td>
+ </tr>
+
+ <tbody id="main_form">
+
+ <tr>
+ <td align="right"><strong>Summary:</strong></td>
+ <td colspan="3">
+ <input name="short_desc" size="60" value="[% short_desc FILTER html %]">
+ </td>
+ </tr>
+
+ <tr>
+ <td align="right"><strong>CC&nbsp;(optional):</strong></td>
+ <td colspan="3">
+ [% INCLUDE global/userselect.html.tmpl
+ id => "cc"
+ name => "cc"
+ value => cc
+ size => 60
+ multiple => 5
+ %]
+ </td>
+ </tr>
+
+ <tr><td align="right" valign="top"><strong>Description:</strong></td>
+ <td colspan="3">
+ <textarea name="comment" rows="10" cols="80">
+ [% comment FILTER html %]</textarea>
+ <br>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="right"><strong>URL&nbsp;(optional):</strong></td>
+ <td colspan="3">
+ <input name="bug_file_loc" size="60"
+ value="[% bug_file_loc FILTER html %]">
+ </td>
+ </tr>
+
+ <tr><td colspan="4">&nbsp;</td></tr>
+
+ <tr>
+ <td colspan="4">
+ <strong>Attachment&nbsp;(optional):</strong>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="right">File:</td>
+ <td colspan="3">
+ <em>Enter the path to the file on your computer.</em><br>
+ <input type="file" id="data" name="data" size="50">
+ <input type="hidden" name="contenttypemethod" value="autodetect" />
+ </td>
+ </tr>
+
+ <tr>
+ <td align="right">Description:</td>
+ <td colspan="3">
+ <em>Describe the attachment briefly.</em><br>
+ <input type="text" id="description" name="description" size="60" maxlength="200">
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <br>
+ <!-- infra -->
+ <input type="checkbox" name="groups" id="groups" value="infra" checked="checked">
+ <label for="groups"><strong>This is an internal issue which should not be publicly visible.</strong></label><br>
+ (please uncheck this box if it isn't)<br>
+ <br>
+ <input type="submit" id="commit" value="Submit Request"><br>
+ <br>
+ Thanks for contacting us. You will be notified by email of any progress made in resolving your request.
+ </td>
+ </tr>
+
+ </tbody>
+
+ <tbody id="service_now_form" style="display:none">
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <br>
+ <input type="submit" value="Go to Service Now">
+ </td>
+ </tr>
+ </tbody>
+ </table>
+</form>
+
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-legal.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-legal.html.tmpl
new file mode 100644
index 000000000..5abe79597
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-legal.html.tmpl
@@ -0,0 +1,226 @@
+[%# 1.0@bugzilla.org %]
+[%# 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 Mozilla Corporation.
+ # Portions created by Mozilla are Copyright (C) 2008 Mozilla
+ # Corporation. All Rights Reserved.
+ #
+ # Contributor(s): Mark Smith <mark@mozilla.com>
+ # Reed Loden <reed@mozilla.com>
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Mozilla Corporation Legal Requests"
+ style_urls = [ 'skins/standard/attachment.css' ]
+ javascript_urls = [ 'js/attachment.js', 'js/field.js' ]
+ yui = [ 'autocomplete' ]
+%]
+
+[% IF user.in_group("mozilla-employee-confidential")
+ OR user.in_group("mozilla-messaging-confidential")
+ OR user.in_group("mozilla-foundation-confidential") %]
+
+<div style='text-align: center; width: 98%; font-size: 2em; font-weight: bold; margin: 10px;'>MoLegal</div>
+
+<p><strong>Welcome to MoLegal.</strong> For legal help please fill in the form below completely.</p>
+
+<p>Legal [% terms.bugs %] are only visible to the reporter, members of the legal team, and those on the
+CC list. This is necessary to maintain attorney-client privilege. Please do not add non-
+employees to the cc list.</p>
+
+<p><strong>All Submissions, And Information Provided In Response To This Request,
+Are Confidential And Subject To The Attorney-Client Privilege And Work Product Doctrine.</strong></p>
+
+<p>If you are requesting legal review of a new product or service, a new feature of an existing product
+ or service, or any type of contract, please go
+ <a href="[% urlbase FILTER none %]enter_bug.cgi?product=mozilla.org&format=moz-project-review">here</a>
+ to kick-off review of your project. If you are requesting another type of legal action, e.g patent analysis,
+ trademark misuse investigation, HR issue, or standards work, please use this form.</p>
+
+<form method="post" action="post_bug.cgi" id="legalRequestForm" enctype="multipart/form-data">
+ <input type="hidden" name="product" value="Legal">
+ <input type="hidden" name="rep_platform" value="All">
+ <input type="hidden" name="op_sys" value="Other">
+ <input type="hidden" name="version" value="unspecified">
+ <input type="hidden" name="priority" value="--">
+ <input type="hidden" name="bug_severity" value="normal">
+ <input type="hidden" name="format" value="legal">
+ <input type="hidden" name="token" value="[% token FILTER html %]">
+ [% IF user.in_group('canconfirm') %]
+ <input type="hidden" name="bug_status" value="NEW">
+ [% END %]
+
+<table>
+
+<tr>
+ <td align="right" width="170px"><strong>Request Type:</strong></td>
+ <td>
+ <select name="component">
+ [%- FOREACH c = product.components %]
+ [% NEXT IF NOT c.is_active %]
+ <option value="[% c.name FILTER html %]"
+ [% " selected=\"selected\"" IF c.name == "General" %]>
+ [% c.name FILTER html -%]
+ </option>
+ [%- END %]
+ </select>
+ </td>
+</tr>
+
+<tr>
+ <td align="right" valign="top">
+ <strong>Goal:</strong>
+ </td>
+ <td colspan="3">
+ <em>Identify the company goal this request maps to.</em><br>
+ <input name="goal" id="goal" size="60" value="[% goal FILTER html %]">
+ </td>
+</tr>
+
+<tr>
+ <td align="right">
+ <strong>Priority to your Team:</strong>
+ </td>
+ <td>
+ <select id="teampriority" name="teampriority">
+ <option value="High">High</option>
+ <option value="Medium">Medium</option>
+ <option value="Low" selected="selected">Low</option>
+ </select>
+ </td>
+</tr>
+
+<tr>
+ <td align="right">
+ <strong>Timeframe for Completion:</strong>
+ </td>
+ <td>
+ <select id="timeframe" name="timeframe">
+ <option value="2 days">2 days</option>
+ <option value="a week">a week</option>
+ <option value="2-4 weeks">2-4 weeks</option>
+ <option value="this will take a while, but please get started soon">
+ this will take a while, but please get started soon</option>
+ <option value="no rush" selected="selected">no rush</option>
+ </select>
+ </td>
+</tr>
+
+<tr>
+ <td align="right" valign="top">
+ <strong>Summary:</strong>
+ </td>
+ <td colspan="3">
+ <em>Include the name of the vendor, partner, product, or other identifier.</em><br>
+ <input name="short_desc" size="60" value="[% short_desc FILTER html %]">
+ </td>
+</tr>
+
+<tr>
+ <td align="right">
+ <strong>CC&nbsp;(optional):</strong>
+ </td>
+ <td colspan="3">
+ [% INCLUDE global/userselect.html.tmpl
+ id => "cc"
+ name => "cc"
+ value => cc
+ size => 60
+ multiple => 5
+ %]
+ </td>
+</tr>
+
+<tr>
+ <td align="right" valign="top">
+ <strong>Name of Other Party:</strong>
+ </td>
+ <td>
+ <em>If applicable, include full legal entity name, address, and any other relevant contact information.</em><br>
+ <textarea id="otherparty" name="otherparty" rows="3" cols="80"></textarea>
+ </td>
+</tr>
+
+<tr>
+ <td align="right">
+ <strong>Business Objective:</strong>
+ </td>
+ <td>
+ <input type="text" name="busobj" id="busobj" value="" size="60" />
+ </td>
+</tr>
+
+<tr>
+ <td align="right" valign="top">
+ <strong>Description:</strong>
+ </td>
+ <td colspan="3">
+ <em>Describe your question, what you want and/or provide any relevant deal terms, restrictions,<br>
+ or provisions that are applicable. Also provide context and background.</em><br>
+ <textarea id="comment" name="comment" rows="10" cols="80">
+ [% comment FILTER html %]</textarea>
+ </td>
+</tr>
+
+<tr>
+ <td align="right"><strong>URL&nbsp;(optional):</strong></td>
+ <td colspan="3">
+ <input name="bug_file_loc" size="60"
+ value="[% bug_file_loc FILTER html %]">
+ </td>
+</tr>
+
+<tr>
+ <td></td>
+ <td colspan=2><strong>Attachment (this is optional)</strong></td>
+</tr>
+
+<tr>
+ <td align="right" valign="top">
+ <strong><label for="data">File:</label></strong>
+ </td>
+ <td>
+ <em>Enter the path to the file on your computer.</em><br>
+ <input type="file" id="data" name="data" size="50">
+ <input type="hidden" name="contenttypemethod" value="autodetect" />
+ </td>
+</tr>
+
+<tr>
+ <td align="right" valign="top">
+ <strong><label for="description">Description:</label></strong>
+ </td>
+ <td>
+ <em>Describe the attachment briefly.</em><br>
+ <input type="text" id="description" name="description" size="60" maxlength="200">
+ </td>
+</tr>
+
+</table>
+
+<br>
+
+ <input type="submit" id="commit" value="Submit Request">
+</form>
+
+<p>Thanks for contacting us. You will be notified by email of any progress made in resolving your request.</p>
+
+[% ELSE %]
+
+<p>Sorry, you do not have access to this page.</p>
+
+[% END %]
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-mdn.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-mdn.html.tmpl
new file mode 100644
index 000000000..f79363c99
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-mdn.html.tmpl
@@ -0,0 +1,279 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% inline_style = BLOCK %]
+strong.required:before {
+ content: "* ";
+ color: red;
+}
+#yui-history-iframe {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 1px;
+ height: 1px;
+ visibility: hidden;
+}
+#standard {
+ margin-top: 2em;
+}
+#standard img {
+ vertical-align: middle;
+}
+#standard a {
+ cursor: pointer;
+}
+[% END %]
+[% inline_javascript = BLOCK %]
+ var Dom = YAHOO.util.Dom;
+ var Event = YAHOO.util.Event;
+ var History = YAHOO.util.History;
+ var mdn = {
+ _initial_state: 'initial',
+ _current_state: 'initial',
+ _current_type: 'Bug',
+ _required_fields: {
+ 'Bug': {
+ 'bug_actions': 'Please enter some text for "What did you do?"',
+ 'bug_actual_results': 'Please enter some text for "What happened?"',
+ 'bug_expected_results': 'Please enter some text for "What should have happened?"',
+ },
+ 'Feature': {
+ 'feature_problem_solving': 'Please enter some text for "What problems would this solve?"',
+ 'feature_audience': 'Please enter some text for "Who would use this?"',
+ 'feature_interface': 'Please enter some text for "What would users see?"',
+ 'feature_process': 'Please enter some text for "What would users do? What would happen as a result?"',
+ },
+ 'Change': {
+ 'change_feature': 'Please enter some text for "What feature should be changed? Please provide the URL of the feature if possible"',
+ 'change_problem_solving': 'Please enter some text for "What problems would this solve?"',
+ 'change_audience': 'Please enter some text for "Who would use this?"',
+ 'change_interface': 'Please enter some text for "What would users see?"',
+ 'change_process': 'Please enter some text for "What would users do? What would happen as a result?"',
+ }
+ },
+ setState: function(state, request_type, no_set_history) {
+ if (state == 'detail') {
+ request_type = request_type || this._getRadioValueByClass('request_type');
+ request_type = request_type.toLowerCase();
+ if (request_type == 'bug') {
+ Dom.get('detail_header').innerHTML = '<h2>[% terms.Bug %] Report</h2>';
+ Dom.get('secure_type').innerHTML = 'report';
+ }
+ if (request_type == 'feature') {
+ Dom.get('detail_header').innerHTML = '<h2>Feature Request</h2>';
+ Dom.get('secure_type').innerHTML = 'request';
+ }
+ if (request_type == 'change') {
+ Dom.get('detail_header').innerHTML = '<h2>Change Request</h2>';
+ Dom.get('secure_type').innerHTML = 'request';
+ }
+ Dom.addClass('detail_' + this._current_type, 'bz_default_hidden');
+ Dom.removeClass('detail_' + request_type, 'bz_default_hidden');
+ this._current_type = request_type;
+ }
+ Dom.addClass(this._current_state + '_form', 'bz_default_hidden');
+ Dom.removeClass(state + '_form', 'bz_default_hidden');
+ this._current_state = state;
+ if (History && !no_set_history) {
+ History.navigate('h', state +
+ (request_type ? '|' + request_type : ''));
+ }
+ return true;
+ },
+ validateAndSubmit: function() {
+ var request_type = this._getRadioValueByClass('request_type');
+ var alert_text = '';
+ if (!isFilledOut('short_desc')) alert_text += 'Please enter a "Summary".\n';
+ for (require_type in this._required_fields) {
+ if (require_type == request_type) {
+ for (field in this._required_fields[require_type]) {
+ if (!isFilledOut(field))
+ alert_text += this._required_fields[require_type][field] + "\n";
+ }
+ }
+ }
+ if (alert_text != '') {
+ alert(alert_text);
+ return false;
+ }
+ var whiteboard = Dom.get('status_whiteboard');
+ whiteboard.value = "[specification][type:" + request_type.toLowerCase() + "]";
+ return true;
+ },
+ _getRadioValueByClass: function(class_name) {
+ var elements = Dom.getElementsByClassName(class_name);
+ for (var i = 0, l = elements.length; i < l; i++) {
+ if (elements[i].checked) return elements[i].value;
+ }
+ },
+ init: function() {
+ var bookmarked_state = History.getBookmarkedState('h');
+ this._initial_state = bookmarked_state || 'initial';
+ try {
+ History.register('h', this._initial_state, mdn.onStateChange);
+ History.initialize('yui-history-field', 'yui-history-iframe');
+ History.onReady(function () {
+ mdn.onStateChange(History.getCurrentState('h'), true);
+ });
+ }
+ catch(e) {
+ console.log('error initializing history: ' + e);
+ History = false;
+ }
+ },
+ onStateChange: function(state, no_set_history) {
+ var state_data = state.split('|');
+ mdn.setState(state_data[0], state_data[1], no_set_history);
+ }
+ };
+ Event.on('show_detail', 'click', function() { mdn.setState('detail'); });
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Mozilla Developer Network Feedback"
+ style = inline_style
+ javascript = inline_javascript
+ yui = [ 'history' ]
+ javascript_urls = [ 'extensions/BMO/web/js/form_validate.js' ]
+%]
+
+<iframe id="yui-history-iframe" src="extensions/BMO/web/yui-history-iframe.txt"></iframe>
+<input id="yui-history-field" type="hidden">
+
+<h1>Mozilla Developer Network Feedback</h1>
+
+<form method="post" action="post_bug.cgi" enctype="multipart/form-data"
+ onSubmit="return mdn.validateAndSubmit();">
+ <input type="hidden" name="format" value="mdn">
+ <input type="hidden" name="product" value="Mozilla Developer Network">
+ <input type="hidden" name="component" value="General">
+ <input type="hidden" name="rep_platform" value="All">
+ <input type="hidden" name="op_sys" value="Other">
+ <input type="hidden" name="version" value="unspecified">
+ <input type="hidden" name="bug_severity" id="bug_severity" value="normal">
+ <input type="hidden" name="token" value="[% token FILTER html %]">
+ <input type="hidden" name="status_whiteboard" id="status_whiteboard" value="">
+
+ <div id="initial_form">
+ <p>
+ <input type="radio" name="request_type" class="request_type"
+ id="request_type_bug" value="Bug" checked="checked">
+ <label for="request_type_bug">Report a [% terms.bug %]</label><br>
+ <input type="radio" name="request_type" class="request_type"
+ id="request_type_feature" value="Feature">
+ <label for="request_type_feature">Request a new feature</label><br>
+ <input type="radio" name="request_type" class="request_type"
+ id="request_type_change" value="Change">
+ <label for="request_type_change">Request a change to an existing feature</label><br>
+ <br>
+ <input id="show_detail" type="button" value="Next">
+ </p>
+ </div>
+
+ <div id="detail_form" class="bz_default_hidden">
+ <p id="detail_header"></p>
+
+ <p id="detail_summary">
+ <strong class="required">Summary</strong><br>
+ <input type="text" name="short_desc" id="short_desc" size="60">
+ </p>
+
+ <div id="detail_bug" class="bz_default_hidden">
+ <p>
+ <strong class="required">What did you do?</strong><br>
+ <textarea name="bug_actions" id="bug_actions" rows="5" cols="60">
+1.&nbsp;
+2.&nbsp;
+3.&nbsp;</textarea>
+ </p>
+ <p>
+ <strong class="required">What happened?</strong><br>
+ <textarea name="bug_actual_results" id="bug_actual_results" rows="5" cols="60"></textarea>
+ </p>
+ <p>
+ <strong class="required">What should have happened?</strong><br>
+ <textarea name="bug_expected_results" id="bug_expected_results" rows="5" cols="60"></textarea>
+ </p>
+ </div>
+
+ <div id="detail_feature" class="bz_default_hidden">
+ <p>
+ <strong class="required">What problems would this solve?</strong><br>
+ <textarea name="feature_problem_solving" id="feature_problem_solving" rows="5" cols="60"></textarea>
+ </p>
+ <p>
+ <strong class="required">Who would use this?</strong><br>
+ <textarea name="feature_audience" id="feature_audience" rows="5" cols="60"></textarea>
+ </p>
+ <p>
+ <strong class="required">What would users see?</strong><br>
+ <textarea name="feature_interface" id="feature_interface" rows="5" cols="60"></textarea>
+ </p>
+ <p>
+ <strong class="required">What would users do? What would happen as a result?</strong><br>
+ <textarea name="feature_process" id="feature_process" rows="5" cols="60"></textarea>
+ </p>
+ </div>
+
+ <div id="detail_change" class="bz_default_hidden">
+ <p>
+ <strong class="required">What feature should be changed? Please provide the URL of the feature if possible.</strong><br>
+ <textarea name="change_feature" id="change_feature" rows="5" cols="60"></textarea>
+ </p>
+ <p>
+ <strong class="required">What problems would this solve?</strong><br>
+ <textarea name="change_problem_solving" id="change_problem_solving" rows="5" cols="60"></textarea>
+ </p>
+ <p>
+ <strong class="required">Who would use this?</strong><br>
+ <textarea name="change_audience" id="change_audience" rows="5" cols="60"></textarea>
+ </p>
+ <p>
+ <strong class="required">What would users see?</strong><br>
+ <textarea name="change_interface" id="change_interface" rows="5" cols="60"></textarea>
+ </p>
+ <p>
+ <strong class="required">What would users do? What would happen as a result?</strong><br>
+ <textarea name="change_process" id="change_process" rows="5" cols="60"></textarea>
+ </p>
+ </div>
+
+ <p id="detail_description">
+ <strong>Is there anything else we should know?</strong><br>
+ <textarea name="description" id="description" rows="5" cols="60"></textarea>
+ </p>
+
+ <p id="detail_secure">
+ <input type="checkbox" name="groups" id="groups"
+ value="[% product.default_security_group FILTER html %]">
+ <label for="groups">
+ <strong>This <span id="secure_type">report</span> is about a problem
+ that is putting users at risk. It should be kept hidden from the public
+ until it is resolved.</strong>
+ </label>
+ </p>
+
+ <input type="submit" id="commit" value="Submit"></td>
+ </div>
+</form>
+
+<div id="standard">
+ <a href="enter_bug.cgi?format=__standard__&product=[% product.name FILTER uri %]">
+ <img src="extensions/BMO/web/images/advanced.png" width="16" height="16" border="0"></a>
+ <a href="enter_bug.cgi?format=__standard__&product=[% product.name FILTER uri %]">
+ Switch to the standard [% terms.bug %] entry form</a>
+</div>
+
+<script>
+ mdn.init();
+</script>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-mobile-compat.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-mobile-compat.html.tmpl
new file mode 100644
index 000000000..a9f0fd2cc
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-mobile-compat.html.tmpl
@@ -0,0 +1,201 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% inline_style = BLOCK %]
+#bug_form th {
+ text-align: right;
+ vertical-align: middle;
+}
+
+#bug_form input[type="text"], #bug_form textarea {
+ width: 100%;
+}
+
+#bug_form textarea {
+ font-family: inherit;
+ font-size: inherit;
+}
+
+#standard_link {
+ margin-top: 2em;
+}
+
+#standard_link img {
+ vertical-align: middle;
+}
+
+#standard_link a {
+ cursor: pointer;
+}
+
+[% END %]
+
+[% inline_javascript = BLOCK %]
+function validateAndSubmit() {
+ var field_errors = {
+ 'op_sys': "Please tell us which product you are using.",
+ 'software_version': "Please tell us which version of the product you are using.",
+ 'bug_file_loc': "Please give the URL of the broken page.",
+ 'short_desc': "Please enter a summary of the problem.",
+ 'desc': "Please tell us how to reproduce the problem.",
+ 'expected_result': "Please tell us what you expected to happen.",
+ 'actual_result': "Please tell us what actually happened.",
+ };
+
+ var alert_text = '';
+
+ for (key in field_errors) {
+ if (!isFilledOut(key)) {
+ alert_text += field_errors[key] + '\n';
+ }
+ }
+
+ if (alert_text != '') {
+ alert(alert_text);
+ return false;
+ }
+
+ return true;
+}
+[% END %]
+
+[% title = "Mobile Web Compatibility Problem" %]
+
+[% PROCESS global/header.html.tmpl
+ title = title
+ style = inline_style
+ javascript = inline_javascript
+ javascript_urls = [ 'extensions/BMO/web/js/form_validate.js']
+%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+
+<h1>[% title FILTER none %]</h1>
+
+<form method="post" action="post_bug.cgi" enctype="multipart/form-data"
+ onSubmit="return validateAndSubmit();">
+ <input type="hidden" name="format" value="mobile-compat">
+ <input type="hidden" name="product" value="Tech Evangelism">
+ <input type="hidden" name="component" value="Mobile">
+ <input type="hidden" name="version" value="unspecified">
+ <input type="hidden" name="bug_status" value="UNCONFIRMED">
+ <input type="hidden" name="rep_platform" value="Other">
+ <input type="hidden" name="bug_severity" value="normal">
+ <input type="hidden" name="status_whiteboard" value="[mobile-compat-form]">
+ <input type="hidden" name="user_agent" value="[% cgi.user_agent() FILTER html %]">
+
+ <input type="hidden" name="token" value="[% token FILTER html %]">
+
+[% IF NOT cgi.user_agent("Mobile") %]
+<p>If possible, it's best to file [% terms.bugs %] using your device's browser. Visit and bookmark &lt;<a href="https://bugzilla.mozilla.org/form.mobile.compat">https://bugzilla.mozilla.org/form.mobile.compat</a>&gt;.</p>
+[% END %]
+
+<table id="bug_form">
+
+<tr>
+ <th class="required">Product</th>
+ <td>
+ <select name="op_sys" id="op_sys">
+ <option value="">Please select...</option>
+ <option value="Gonk (Firefox OS)">Firefox OS</option>
+ <option value="Android">Firefox for Android</option>
+ </select>
+ </td>
+</tr>
+
+<tr>
+ <th class="required">Product Version</th>
+ <td>
+ <input type="text" name="software_version" id="software_version" size="60"
+ placeholder="Software version - see About box or Preferences">
+ </td>
+</tr>
+
+<tr>
+ <th class="required">Full Web Page Address</th>
+ <td>
+ <input type="text" name="bug_file_loc" id="bug_file_loc" size="60"
+ placeholder="e.g. http://www.example.com/page.html">
+ </td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+</tr>
+
+<tr>
+ <th class="required">Problem Summary</th>
+ <td>
+ <input type="text" name="short_desc" id="short_desc" size="60"
+ placeholder="Describe the specific problem with the page in one sentence">
+ </td>
+</tr>
+
+<tr>
+ <th class="required">Steps To Reproduce</th>
+ <td>
+ <textarea id="desc" name="desc" cols="50" rows="5">1.
+2.
+3.
+...</textarea>
+ </td>
+</tr>
+
+<tr>
+ <th class="required">Expected Result</th>
+ <td>
+ <input type="text" id="expected_result" name="expected_result" size="60"
+ placeholder="What were you expecting to happen?">
+ </td>
+</tr>
+
+<tr>
+ <th class="required">Actual Result</th>
+ <td>
+ <input type="text" name="actual_result" id="actual_result" size="60"
+ placeholder="What happened instead?">
+ </td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+</tr>
+
+<tr>
+ <th>Device Information</th>
+ <td>
+ <input type="text" name="device" id="device" size="60"
+ placeholder="Make and model">
+ </td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+ <td><input type="submit" id="commit" value="Submit Issue"></td>
+</tr>
+
+</table>
+</form>
+
+[ <span class="required_star">*</span> <span class="required_explanation">Required Field</span> ]
+
+<div id="standard_link">
+ <a href="enter_bug.cgi?format=__standard__&amp;product=[% product.name FILTER uri %]">
+ <img src="extensions/BMO/web/images/advanced.png" width="16" height="16" border="0"></a>
+ <a href="enter_bug.cgi?format=__standard__&amp;product=[% product.name FILTER uri %]">
+ Switch to the standard [% terms.bug %] entry form</a>
+</div>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-mozlist.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-mozlist.html.tmpl
new file mode 100644
index 000000000..38c08c72f
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-mozlist.html.tmpl
@@ -0,0 +1,177 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Mozilla Discussion Forum"
+ javascript_urls = [ 'extensions/BMO/web/js/form_validate.js',
+ 'js/field.js' ]
+ yui = [ 'autocomplete' ]
+ style = ".mandatory{color:red;font-size:80%;}"
+%]
+
+<script type="text/javascript">
+<!--
+ function trySubmit() {
+ var alert_text = "";
+
+ if (!isFilledOut('listName')) {
+ alert_text += "Please enter the list name\n";
+ }
+
+ if (!isValidEmail(document.getElementById('listAdmin').value)) {
+ alert_text += "Please enter a valid email address for the list administrator\n";
+ }
+
+ if (alert_text) {
+ alert(alert_text);
+ return false;
+ }
+
+ var listName = document.getElementById('listName').value;
+ document.getElementById('short_desc').value = "Discussion Forum: " + listName;
+
+ return true;
+ }
+// -->
+</script>
+
+<p>
+ <b>Create a Mozilla Discussion Forum</b><br>
+ This option gives you a Mozilla <a
+ href="https://www.mozilla.org/about/forums/">Discussion Forum</a>.
+ These are the normal mechanism for public discussion in the Mozilla
+ project. They are made up of a mailing list on
+ <b>lists.mozilla.org</b>, a newsgroup on <b>news.mozilla.org</b> and
+ a <b>Google Group</b> (which maintains the list archives), all linked
+ together. Users can add and remove themselves.
+</p>
+
+<div id="message">
+ <b>Note:</b>
+ You must use <a href="https://mozilla.service-now.com/"><b>Service Now</b></a>
+ to request a distribution list or a standard mailing list.
+</div>
+<br>
+
+<form method="post" action="post_bug.cgi" id="mozListRequestForm"
+ enctype="multipart/form-data" onSubmit="return trySubmit();">
+ <input type="hidden" id="format" name="format" value="mozlist">
+ <input type="hidden" id="product" name="product" value="mozilla.org">
+ <input type="hidden" id="rep_platform" name="rep_platform" value="All">
+ <input type="hidden" id="op_sys" name="op_sys" value="Other">
+ <input type="hidden" id="priority" name="priority" value="--">
+ <input type="hidden" id="version" name="version" value="other">
+ <input type="hidden" id="short_desc" name="short_desc" value="">
+ <input type="hidden" id="component" name="component" value="Discussion Forums">
+ <input type="hidden" id="bug_severity" name="bug_severity" value="normal">
+ <input type="hidden" id="token" name="token" value="[% token FILTER html %]">
+
+ <table>
+ <tr>
+ <th class="field_label">
+ <span class="mandatory" title="Required">*</span> List Name:
+ </th>
+ <td>
+ The desired name for the newsgroup. Should start with 'mozilla.' and fit somewhere
+ in the hierarchy described <a href="https://www.mozilla.org/about/forums/">here</a>.<br>
+ <input name="listName" id="listName" size="60" value="[% listName FILTER html %]">
+ </td>
+ </tr>
+ <tr>
+ <th class="field_label">
+ <span class="mandatory" title="Required">*</span> List Administrator:
+ </th>
+ <td>
+ <b>Note:</b>The list administrator is also initially considered to be the list moderator
+ and will be responsible for moderation tasks unless delegated to someone else. For
+ convenience, [% terms.Bugzilla %] user accounts will autocomplete but it does not have
+ to be a [% terms.Bugzilla %] account.<br>
+ [% INCLUDE global/userselect.html.tmpl
+ id => "listAdmin"
+ name => "listAdmin"
+ value => ""
+ size => 60
+ multiple => 5
+ %]
+ </td>
+ </tr>
+ <tr>
+ <td class="field_label">Short Description:</th>
+ <td>
+ This will be shown to users on the index of lists on the server.<br>
+ <input name="listShortDesc" id="listShortDesc" size="60" value="[% listShortDesc FILTER html %]">
+ </td>
+ </tr>
+ <tr>
+ <td class="field_label">Long Description:</th>
+ <td>
+ This will be shown at the top of the list's listinfo page.<br>
+ [% INCLUDE global/textarea.html.tmpl
+ name = 'listLongDesc'
+ id = 'listLongDesc'
+ minrows = 10
+ maxrows = 25
+ cols = constants.COMMENT_COLS
+ defaultcontent = listLongDesc
+ %]
+ </td>
+ </tr>
+ <tr>
+ <th class="field_label">Additional Comments:</th>
+ <td>
+ Justification for the list, special instructions, etc.<br>
+ [% INCLUDE global/textarea.html.tmpl
+ name = 'comment'
+ id = 'comment'
+ minrows = 10
+ maxrows = 25
+ cols = constants.COMMENT_COLS
+ defaultcontent = comment
+ %]
+ </td>
+ </tr>
+ <tr>
+ <th class="field_label">CC:</th>
+ <td>
+ [% INCLUDE global/userselect.html.tmpl
+ id => "cc"
+ name => "cc"
+ value => cc
+ size => 60
+ multiple => 5
+ %]
+ </td>
+ </tr>
+ <tr>
+ <th class="field_label">URL:</th>
+ <td colspan="3">
+ <input name="bug_file_loc" size="60"
+ value="[% bug_file_loc FILTER html %]">
+ </td>
+ </tr>
+ <tr>
+ <td align="right">
+ <input type="checkbox" name="groups" id="group_35" value="infra">
+ </td>
+ <td>
+ <label for="group_35"><b>This is an internal issue which should not be publicly visible.</b></label>
+ </td>
+ </tr>
+ </table>
+
+ <input type="submit" id="commit" value="Submit Request">
+
+ <p>
+ Thanks for contacting us. You will be notified by email of any progress made
+ in resolving your request.
+ </p>
+</form>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-mozpr.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-mozpr.html.tmpl
new file mode 100644
index 000000000..f231ea3b9
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-mozpr.html.tmpl
@@ -0,0 +1,683 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% inline_style = BLOCK %]
+#pr_form {
+ padding: 10px;
+ width: 600px;
+}
+
+#pr_form input[type="text"], #pr_form textarea {
+ width: 100%;
+ margin-bottom: 2px;
+}
+
+#pr_form .calendar {
+ width: 100px;
+}
+
+#pr_form .user {
+ width: 300px;
+}
+
+#pr_form select {
+ width: 200px;
+}
+
+#pr_form .required:after {
+ content: " *";
+ color: red;
+}
+
+#pr_form .missing {
+ box-shadow: 0px 0px 5px red;
+}
+
+#pr_form label {
+ font-weight: bold;
+ display: block;
+}
+
+#pr_form label.normal {
+ font-weight: normal;
+ display: inline;
+}
+
+#pr_form .calendar_button {
+ margin-top: 0.5em;
+}
+
+#pr_form .desc {
+ padding-bottom: 3px;
+}
+
+#pr_form .field {
+ margin-bottom: 10px;
+}
+
+#pr_form .indent {
+ margin-left: 30px;
+}
+
+#pr_form textarea {
+ font-family: inherit;
+ font-size: inherit;
+}
+
+#pr_form .head {
+ font-weight: bold;
+ border-top: 1px solid silver;
+ border-bottom: 1px solid silver;
+ padding: 5px;
+ margin: 1em 0;
+ background: #ddd;
+}
+
+#pr_form fieldset {
+ border: none;
+}
+
+#pr_form .extra {
+ font-style: italic;
+}
+
+#pr_form .extra a {
+ text-decoration: underline;
+}
+
+#pr_form #commit {
+ margin-top: 20px;
+}
+
+#pr_form .linked {
+ display: block;
+ margin-top: 2px;
+ width: 300px;
+}
+
+[% END %]
+
+[% inline_javascript = BLOCK %]
+var pr_inited = false;
+
+function init_listener(id, event, fn) {
+ YAHOO.util.Event.addListener(id, event, fn);
+ bz_fireEvent(document.getElementById(id), event);
+}
+
+function toggle_linked(id, value, suffix) {
+ var el = document.getElementById(id);
+ var show = el.type == 'checkbox' ? el.checked : el.value == value;
+ if (show) {
+ var linked = document.getElementById(id + suffix);
+ YAHOO.util.Dom.addClass(linked, 'linked');
+ YAHOO.util.Dom.removeClass(linked, 'bz_default_hidden');
+ if (pr_inited && linked.nodeName == "INPUT") {
+ linked.focus();
+ linked.select();
+ }
+ }
+ else {
+ YAHOO.util.Dom.addClass(id + suffix, 'bz_default_hidden');
+ }
+}
+
+function init_other(id) {
+ init_listener(id, 'change', function(o) {
+ toggle_linked(id, 'Other:', '_other');
+ });
+}
+
+YAHOO.util.Event.onDOMReady(function() {
+ init_listener('metrica', 'change', function(o) {
+ toggle_linked('metrica', 'Yes', '_extra');
+ });
+ init_listener('budget', 'change', function(o) {
+ toggle_linked('budget', 'Extra', '_extra');
+ });
+ init_listener('proj_mat_online', 'click', function(o) {
+ toggle_linked('proj_mat_online', 0, '_extra');
+ });
+ init_listener('proj_mat_file', 'click', function(o) {
+ toggle_linked('proj_mat_file', 0, '_extra');
+ });
+ init_listener('pr_mat_online', 'click', function(o) {
+ toggle_linked('pr_mat_online', 0, '_extra');
+ });
+ init_listener('pr_mat_file', 'click', function(o) {
+ toggle_linked('pr_mat_file', 0, '_extra');
+ });
+
+ init_other('pr_owner');
+ init_other('group_focus');
+ init_other('project_type');
+ init_other('region');
+ init_other('press_center');
+ init_other('internal_resources');
+ init_other('external_resources');
+ init_other('localization');
+ init_other('audience');
+
+ pr_inited = true;
+});
+
+function validate_other(id, value, suffix) {
+ var el = document.getElementById(id);
+ if (!value) value = 'Other:';
+ if (!suffix) suffix = '_other';
+ if (!el) {
+ console.error('Failed to find element: ' + elem_id);
+ return false;
+ }
+ if (el.type == 'checkbox') {
+ if (!el.checked) return true;
+ }
+ else if (el.value != value) {
+ return true;
+ }
+ return isFilledOut(id + suffix);
+}
+
+function validate_form() {
+ var Dom = YAHOO.util.Dom;
+
+ var old_missing = Dom.getElementsByClassName('missing');
+ for (var i = 0, il = old_missing.length; i < il; i++) {
+ Dom.removeClass(old_missing[i], 'missing');
+ }
+
+ var missing = [];
+ if (!isFilledOut('short_desc')) missing.push(['short_desc', 'Project Title']);
+ if (!isFilledOut('desc')) missing.push(['desc', 'Project Description and Scope']);
+
+ if (!isFilledOut('start_date')) missing.push(['start_date', 'Start Date']);
+ if (!isFilledOut('announce_date')) missing.push(['announce_date', 'Announcement Date']);
+ if (!isFilledOut('deadline')) missing.push(['deadline', 'Internal Deadline']);
+
+ if (!isFilledOut('pr_owner')) missing.push(['pr_owner', 'Project PR Owner']);
+ if (!isFilledOut('owner')) missing.push(['owner', 'Project Owner']);
+
+ if (!isFilledOut('rasci_a')) missing.push(['rasci_a', 'RASCI Approver']);
+
+ if (!isFilledOut('tier')) missing.push(['tier', 'Tier']);
+ if (!isFilledOut('project_type')) missing.push(['project_type', 'Project Type']);
+ if (!isFilledOut('pr_approach')) missing.push(['pr_approach', 'PR Approach']);
+ if (!isFilledOut('group_focus')) missing.push(['group_focus', 'Product Group Focus']);
+ if (!validate_other('group_focus')) missing.push(['group_focus', 'Product Group Focus - Other']);
+ if (!isFilledOut('region')) missing.push(['region', 'Region']);
+ if (!validate_other('region')) missing.push(['region', 'Region - Other']);
+
+ if (!isFilledOut('project_goals')) missing.push(['project_goals', 'Project Goals']);
+ if (!isFilledOut('pr_goals')) missing.push(['pr_goals', 'PR Goals']);
+ if (!isFilledOut('company_goal')) missing.push(['company_goal', 'Company Goal']);
+ if (!isOneChecked(document.forms.pr_form.audience))
+ missing.push(['audience_group', 'Audiences']);
+ if (!validate_other('audience')) missing.push(['audience', 'Audience - Other']);
+ if (!isFilledOut('key_messages')) missing.push(['key_messages', 'Key Messages']);
+
+ if (Dom.get('proj_mat_online').checked) {
+ if (!isFilledOut('proj_mat_online_desc')) missing.push(['proj_mat_online_desc', 'Project Materials - Online Description']);
+ if (!isFilledOut('proj_mat_online_link')) missing.push(['proj_mat_online_link', 'Project Materials - Online Link']);
+ }
+ if (Dom.get('proj_mat_file').checked) {
+ if (!isFilledOut('proj_mat_file_desc')) missing.push(['proj_mat_file_desc', 'Project Materials - Upload Description']);
+ if (!isFilledOut('proj_mat_file_attach')) missing.push(['proj_mat_file_attach', 'Project Materials - Upload File']);
+ }
+ if (Dom.get('pr_mat_online').checked) {
+ if (!isFilledOut('pr_mat_online_desc')) missing.push(['pr_mat_online_desc', 'PR Project Materials - Online Description']);
+ if (!isFilledOut('pr_mat_online_link')) missing.push(['pr_mat_online_link', 'PR Project Materials - Online Link']);
+ }
+ if (Dom.get('pr_mat_file').checked) {
+ if (!isFilledOut('pr_mat_file_desc')) missing.push(['pr_mat_file_desc', 'PR Project Materials - Upload Description']);
+ if (!isFilledOut('pr_mat_file_attach')) missing.push(['pr_mat_file_attach', 'PR Project Materials - Upload File']);
+ }
+
+ if (!validate_other('press_center')) missing.push(['press_center', 'Press Center Update - Other']);
+ if (!validate_other('internal_resources')) missing.push(['internal_resources', 'Internal Resources Needed - Other']);
+ if (!validate_other('external_resources')) missing.push(['external_resources', 'External Resources Needed - Other']);
+ if (!validate_other('localization')) missing.push(['localization', 'Localization Needed - Other']);
+
+ if (!isFilledOut('budget')) missing.push(['budget', 'Budget']);
+ if (!validate_other('budget', 'Extra', '_extra')) missing.push(['budget', 'Budget - Extra']);
+
+ if (missing.length) {
+ var missing_text = [];
+ for (var i = 0, il = missing.length; i < il; i++) {
+ Dom.addClass(missing[i][0], 'missing');
+ missing_text.push(missing[i][1]);
+ }
+ if (missing_text.length == 1) {
+ alert("The field '" + missing_text[0] + "' is required.");
+ }
+ else {
+ alert("The following fields are required:\n- " + missing_text.join("\n- "));
+ }
+ return false;
+ }
+
+ return true;
+}
+
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = "PR Project Form"
+ style = inline_style
+ javascript = inline_javascript
+ javascript_urls = [ 'extensions/BMO/web/js/form_validate.js',
+ 'js/field.js', 'js/util.js' ]
+ yui = [ "autocomplete", "calendar" ]
+%]
+
+[% UNLESS user.in_group('pr-private') %]
+ <div id="error_msg" class="throw_error">
+ This form is only available to members of the Mozilla PR team.
+ </div>
+ [% PROCESS global/footer.html.tmpl %]
+ [% RETURN %]
+[% END %]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+
+<form id="pr_form" name="pr_form" method="post" action="post_bug.cgi"
+ enctype="multipart/form-data" onSubmit="return validate_form()">
+<input type="hidden" name="format" value="mozpr">
+<input type="hidden" name="product" value="Mozilla PR">
+<input type="hidden" name="component" value="Projects">
+<input type="hidden" name="rep_platform" value="All">
+<input type="hidden" name="op_sys" value="Other">
+<input type="hidden" name="version" value="unspecified">
+<input type="hidden" name="bug_severity" value="normal">
+<input type="hidden" name="group" value="pr-private">
+<input type="hidden" name="assigned_to" id="assigned_to" value="nobody@mozilla.org">
+<input type="hidden" name="token" value="[% token FILTER html %]">
+
+<div class="head">
+ PR Project Form
+</div>
+
+<div class="field">
+ <label for="short_desc" class="required">Project Title</label>
+ <input type="text" name="short_desc" id="short_desc" placeholder="Your project's title">
+</div>
+
+<div class="field">
+ <label for="desc" class="required">Project Description and Scope</label>
+ <textarea name="desc" id="desc" placeholder="A short description of your PR project"></textarea>
+</div>
+
+<div class="head">
+ Timings
+</div>
+
+<div class="field">
+ <label for="start_date" class="required">Start Date</label>
+ <input name="start_date" id="start_date" value="" class="calendar"
+ onchange="updateCalendarFromField(this)">
+ <button type="button" class="calendar_button" id="button_calendar_start_date"
+ onclick="showCalendar('start_date')">
+ <span>Calendar</span>
+ </button>
+ <div id="con_calendar_start_date"></div>
+ <script type="text/javascript">
+ createCalendar('start_date')
+ </script>
+</div>
+
+<div class="field">
+ <label for="announce_date" class="required">Announcement Date</label>
+ <input name="announce_date" id="announce_date" value="" class="calendar"
+ onchange="updateCalendarFromField(this)">
+ <button type="button" class="calendar_button" id="button_calendar_announce_date"
+ onclick="showCalendar('announce_date')">
+ <span>Calendar</span>
+ </button>
+ <div id="con_calendar_announce_date"></div>
+ <script type="text/javascript">
+ createCalendar('announce_date')
+ </script>
+</div>
+
+<div class="field">
+ <label for="deadline" class="required">Internal Deadline</label>
+ <input name="deadline" id="deadline" value="" class="calendar"
+ onchange="updateCalendarFromField(this)">
+ <button type="button" class="calendar_button" id="button_calendar_deadline"
+ onclick="showCalendar('deadline')">
+ <span>Calendar</span>
+ </button>
+ <div id="con_calendar_deadline"></div>
+ <script type="text/javascript">
+ createCalendar('deadline')
+ </script>
+</div>
+
+<div class="head">
+ Owners
+</div>
+
+<div class="field">
+ <label for="pr_owner" class="required">Project PR Owner</label>
+ <select name="pr_owner" id="pr_owner">
+ <option value=""></option>
+ <option value="ahubert@mozilla.com">Aurelien Hubert</option>
+ <option value="bhueppe@mozilla.com">Barbara Hüppe</option>
+ <option value="ej@mozilla.com">Erica Jostedt</option>
+ <option value="jokelly@mozilla.com">Justin O'Kelly</option>
+ <option value="kshaw@mozilla.com">Karolina Shaw</option>
+ <option value="kshaw@mozilla.com">Mike Manning</option>
+ <option value="lnapoli@mozilla.com">Laura Napoli</option>
+ <option value="pjarratt@mozilla.com">Paul Jarratt</option>
+ <option value="tnitot@mozilla.com">Tristan Nitot</option>
+ <option value="vponell@mozilla.com">Valerie Ponell</option>
+ <option value="Other:">Other:</option>
+ </select>
+ <input name="pr_owner_other" id="pr_owner_other" class="bz_default_hidden">
+</div>
+
+<div class="field">
+ <label for="owner" class="required">Project Owner</label>
+ <input name="owner" id="owner" class="user">
+</div>
+
+<div class="head">
+ RASCI
+</div>
+
+<div class="field">
+ <label for="rasci_r">Responsible</label>
+ <input name="rasci_r" id="rasci_r" class="user">
+</div>
+
+<div class="field">
+ <label for="rasci_a" class="required">Approver</label>
+ <input name="rasci_a" id="rasci_a" class="user">
+</div>
+
+<div class="field">
+ <label for="rasci_s">Supporter</label>
+ <input name="rasci_s" id="rasci_s" class="user">
+</div>
+
+<div class="field">
+ <label for="rasci_c">Consultant</label>
+ <input name="rasci_c" id="rasci_c" class="user">
+</div>
+
+<div class="field">
+ <label for="rasci_i">Informed</label>
+ <input name="rasci_i" id="rasci_i" class="user">
+</div>
+
+<div class="head">
+ Details
+</div>
+
+<div class="field">
+ <label for="tier" class="required">Tier</label>
+ <select name="tier" id="tier">
+ <option value=""></option>
+ <option value="1">1</option>
+ <option value="2">2</option>
+ <option value="3">3</option>
+ </select>
+</div>
+
+<div class="field">
+ <label for="project_type" class="required">Project Type</label>
+ <select name="project_type" id="project_type">
+ <option value=""></option>
+ <option>Announcement</option>
+ <option>Speaking and Events</option>
+ <option>Planning</option>
+ <option>Messaging and Materials</option>
+ <option>Campaign</option>
+ <option>Other:</option>
+ </select>
+ <input name="project_type_other" id="project_type_other" class="bz_default_hidden">
+</div>
+
+<div class="field">
+ <label for="pr_approach" class="required">PR Approach</label>
+ <select name="pr_approach" id="pr_approach">
+ <option value=""></option>
+ <option value="Proactive">Proactive</option>
+ <option value="Reactive">Reactive</option>
+ </select>
+</div>
+
+<div class="field">
+ <label for="group_focus" class="required">Product Group Focus</label>
+ <select name="group_focus" id="group_focus">
+ <option value=""></option>
+ <option>Firefox Desktop</option>
+ <option>Firefox for Android</option>
+ <option>Marketplace</option>
+ <option>Developer Tools</option>
+ <option>Cloud</option>
+ <option>Firefox OS</option>
+ <option>Corporate / Business Support</option>
+ <option>Other:</option>
+ </select>
+ <input name="group_focus_other" id="group_focus_other" class="bz_default_hidden">
+</div>
+
+<div class="field">
+ <label for="region" class="required">Region</label>
+ <select name="region" id="region">
+ <option value=""></option>
+ <option>Global</option>
+ <option>US</option>
+ <option>LatAm</option>
+ <option>Europe</option>
+ <option>Africa</option>
+ <option>Asia</option>
+ <option>Other:</option>
+ </select>
+ <input name="region_other" id="region_other" class="bz_default_hidden">
+</div>
+
+<div class="head">
+ Goals, Audience, and Messages
+</div>
+
+<div class="field">
+ <label for="project_goals" class="required">Project Goals</label>
+ <textarea name="project_goals" id="project_goals"></textarea>
+</div>
+
+<div class="field">
+ <label for="pr_goals" class="required">PR Goals</label>
+ <textarea name="pr_goals" id="pr_goals"></textarea>
+</div>
+
+<div class="field">
+ <label for="company_goal" class="required">Company Goal</label>
+ <select name="company_goal" id="company_goal">
+ <option value=""></option>
+ <option>Scale Firefox OS</option>
+ <option>Add Services to our Product Lines</option>
+ <option>Get Firefox on a Growth Trajectory</option>
+ <option>Invest in Sustainability</option>
+ <option>Risk Mitigation</option>
+ </select>
+</div>
+
+<div class="field" id="audience_group">
+ <label class="required">Audiences</label>
+ <input type="checkbox" name="audience" id="audience_business" value="Business Press">
+ <label for="audience_business" class="normal">Business Press</label><br>
+ <input type="checkbox" name="audience" id="audience_con_tech" value="Consumer Tech">
+ <label for="audience_con_tech" class="normal">Consumer Tech</label><br>
+ <input type="checkbox" name="audience" id="audience_con" value="Consumer">
+ <label for="audience_con" class="normal">Consumer</label><br>
+ <input type="checkbox" name="audience" id="audience_dev" value="Developer">
+ <label for="audience_dev" class="normal">Developer</label><br>
+ <input type="checkbox" name="audience" id="audience" value="Other:">
+ <label for="audience" class="normal">Other:</label><br>
+ <input name="audience_other" id="audience_other" class="bz_default_hidden indent">
+</div>
+
+<div class="field">
+ <label for="key_messages" class="required">Key Messages</label>
+ <textarea name="key_messages" id="key_messages" placeholder="State (draft) key messages of what we would like to get across to
+ press for this project."></textarea>
+</div>
+
+<div class="head">
+ Materials
+</div>
+
+<div class="field">
+ <label>Project Materials</label>
+ <div>
+ <input type="checkbox" name="proj_mat_online" id="proj_mat_online">
+ <label class="normal" for="proj_mat_online">
+ Online Documentation (e.g. WAVE Dashboard)
+ </label>
+ <div id="proj_mat_online_extra" class="bz_default_hidden indent">
+ <label for="proj_mat_online_desc" class="required">Material Description</label>
+ <input type="text" name="proj_mat_online_desc" id="proj_mat_online_desc">
+ <label for="proj_mat_online_link" class="required">Material Link</label>
+ <input type="text" name="proj_mat_online_link" id="proj_mat_online_link">
+ </div>
+ </div>
+ <div>
+ <input type="checkbox" name="proj_mat_file" id="proj_mat_file">
+ <label class="normal" for="proj_mat_file">
+ Upload File
+ </label>
+ <div id="proj_mat_file_extra" class="bz_default_hidden indent">
+ <label for="proj_mat_file_desc" class="required">File Description</label>
+ <input type="text" name="proj_mat_file_desc" id="proj_mat_file_desc">
+ <label for="proj_mat_file_attach" class="required">File Upload</label>
+ <input type="file" name="proj_mat_file_attach" id="proj_mat_file_attach">
+ </div>
+ </div>
+</div>
+
+<div class="field">
+ <label>PR Project Materials</label>
+ <div>
+ <input type="checkbox" name="pr_mat_online" id="pr_mat_online">
+ <label class="normal" for="pr_mat_online">
+ Online Documentation (e.g. comms plan)
+ </label>
+ <div id="pr_mat_online_extra" class="bz_default_hidden indent">
+ <label for="pr_mat_online_desc" class="required">Material Description</label>
+ <input type="text" name="pr_mat_online_desc" id="pr_mat_online_desc">
+ <label for="pr_mat_online_link" class="required">Material Link</label>
+ <input type="text" name="pr_mat_online_link" id="pr_mat_online_link">
+ </div>
+ </div>
+ <div>
+ <input type="checkbox" name="pr_mat_file" id="pr_mat_file">
+ <label class="normal" for="pr_mat_file">
+ Upload File
+ </label>
+ <div id="pr_mat_file_extra" class="bz_default_hidden indent">
+ <label for="pr_mat_file_desc" class="required">File Description</label>
+ <input type="text" name="pr_mat_file_desc" id="pr_mat_file_desc">
+ <label for="pr_mat_file_attach" class="required">File Upload</label>
+ <input type="file" name="pr_mat_file_attach" id="pr_mat_file_attach">
+ </div>
+ </div>
+</div>
+
+<div class="head">
+ Requirements
+</div>
+
+<div class="field">
+ <label for="metrica">Metrica Coverage Reporting Scope</label>
+ <select name="metrica" id="metrica">
+ <option>No</option>
+ <option>Yes</option>
+ </select>
+ <div id="metrica_extra" class="bz_default_hidden extra">
+ Please fill out the
+ <a href="https://basecamp.com/2256351/projects/2980983/messages/12008835" target="_blank">Metrica form</a>
+ and submit to Metrica no later than a week before project starts.
+ </div>
+</div>
+
+<div class="field" id="press_center_group">
+ <label>Press Center Update</label>
+ <input type="checkbox" name="press_center" id="press_center_post" value="Post on press pages">
+ <label for="press_center_post" class="normal">Post on press pages</label><br>
+ <input type="checkbox" name="press_center" id="press_center_library" value="Media Library update">
+ <label for="press_center_library" class="normal">Media Library update</label><br>
+ <input type="checkbox" name="press_center" id="press_center" value="Other:">
+ <label for="press_center" class="normal">Other:</label><br>
+ <input name="press_center_other" id="press_center_other" class="bz_default_hidden indent">
+</div>
+
+<div class="field" id="internal_resources_group">
+ <label>Internal Resources Needed</label>
+ <input type="text" name="resources" id="resources">
+ <input type="checkbox" name="internal_resources" id="internal_resources_spokesperson" value="Spokesperson">
+ <label for="internal_resources_spokesperson" class="normal">Spokesperson</label><br>
+ <input type="checkbox" name="internal_resources" id="internal_resources_staff" value="Demo Staff">
+ <label for="internal_resources_staff" class="normal">Demo Staff</label><br>
+ <input type="checkbox" name="internal_resources" id="internal_resources_support" value="Creative Support">
+ <label for="internal_resources_support" class="normal">Creative Support</label><br>
+ <input type="checkbox" name="internal_resources" id="internal_resources" value="Other:">
+ <label for="internal_resources" class="normal">Other:</label><br>
+ <input name="internal_resources_other" id="internal_resources_other" class="bz_default_hidden indent">
+</div>
+
+<div class="field" id="external_resources_group">
+ <label>External Resources Needed</label>
+ <input type="checkbox" name="external_resources" id="external_resources_pr" value="PR Agency Support">
+ <label for="external_resources_pr" class="normal">PR Agency Support</label><br>
+ <input type="checkbox" name="external_resources" id="external_resources_design" value="Design Support">
+ <label for="external_resources_design" class="normal">Design Support</label><br>
+ <input type="checkbox" name="external_resources" id="external_resources_community" value="Community Support">
+ <label for="external_resources_community" class="normal">Community Support</label><br>
+ <input type="checkbox" name="external_resources" id="external_resources" value="Other:">
+ <label for="external_resources" class="normal">Other:</label><br>
+ <input name="external_resources_other" id="external_resources_other" class="bz_default_hidden indent">
+</div>
+
+<div class="field">
+ <label for="localization">Localization Needed</label>
+ <select name="localization" id="localization">
+ <option>None</option>
+ <option>Yes - Agency Localization</option>
+ <option>Yes - Community Localization</option>
+ <option>Other:</option>
+ </select>
+ <input name="localization_other" id="localization_other" class="bz_default_hidden">
+</div>
+
+<div class="head">
+ Budget
+</div>
+
+<div class="field">
+ <label for="budget" class="required">Budget</label>
+ <select name="budget" id="budget">
+ <option value=""></option>
+ <option value="Covered">Covered in budget</option>
+ <option value="Extra">Extra budget required:</option>
+ </select>
+ <input name="budget_extra" id="budget_extra" class="bz_default_hidden">
+</div>
+
+<input type="submit" id="commit" value="Submit">
+
+<p>
+ [ <span class="required_star">*</span> <span class="required_explanation">Required Field</span> ]
+</p>
+
+</form>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-poweredby.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-poweredby.html.tmpl
new file mode 100644
index 000000000..e231cd9d5
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-poweredby.html.tmpl
@@ -0,0 +1,87 @@
+[%# 1.0@bugzilla.org %]
+[%# 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 <gerv@gerv.net>
+ # Ville SkyttŠ <ville.skytta@iki.fi>
+ # John Hoogstrate <hoogstrate@zeelandnet.nl>
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Powered by Mozilla Logo Requests"
+%]
+
+[% USE Bugzilla %]
+
+<p>If you are interested in using the <a href="http://www.mozilla.org/poweredby">Powered by Mozilla logo</a>,
+please provide some information about your application or product.</p>
+
+<p><strong>Please use this form for Powered by Mozilla logo requests only.</strong></p>
+
+<form method="post" action="post_bug.cgi" id="tmRequestForm">
+
+ <input type="hidden" name="product" value="Marketing">
+ <input type="hidden" name="component" value="Trademark Permissions">
+ <input type="hidden" name="bug_severity" value="enhancement">
+ <input type="hidden" name="rep_platform" value="All">
+ <input type="hidden" name="priority" value="--">
+ <input type="hidden" name="op_sys" value="Other">
+ <input type="hidden" name="version" value="unspecified">
+ <input type="hidden" name="assigned_to" value="dboswell@mozilla.com">
+ <input type="hidden" name="cc" value="liz@mozilla.com">
+ <input type="hidden" name="groups" value="marketing-private">
+ <input type="hidden" name="token" value="[% token FILTER html %]">
+
+ <table>
+ <tr>
+ <td align="right"><strong>Application or Product Name:</strong></td>
+ <td colspan="3">
+ <input name="short_desc" size="60" value="Powered by Mozilla request for: [% short_desc FILTER html %]">
+ </td>
+ </tr>
+
+ <tr>
+ <td align="right"><strong>URL&nbsp;(optional):</strong></td>
+ <td colspan="3">
+ <input name="bug_file_loc" size="60"
+ value="[% bug_file_loc FILTER html %]">
+ </td>
+ </tr>
+
+ <tr><td align="right" valign="top"><strong>Comments&nbsp;(optional):</strong></td>
+ <td colspan="3">
+ <textarea name="comment" rows="10" cols="80">
+ [% comment FILTER html %]</textarea>
+ <br>
+ </td>
+ </tr>
+
+ </table>
+
+ <br>
+
+ <input type="submit" id="commit" value="Submit Request">
+</form>
+
+<p>Thanks for contacting us.
+ You will be notified by email of any progress made in resolving your
+ request.
+</p>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-presentation.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-presentation.html.tmpl
new file mode 100644
index 000000000..7819818b3
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-presentation.html.tmpl
@@ -0,0 +1,11 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/redirect.html.tmpl
+ url = "https://air.mozilla.org/requests"
+%]
diff --git a/extensions/BMO/template/en/default/bug/create/create-privacy-data.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-privacy-data.html.tmpl
new file mode 100644
index 000000000..b99953282
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-privacy-data.html.tmpl
@@ -0,0 +1,219 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% inline_style = BLOCK %]
+ #bug_form input[type=text], #bug_form input[type=file], #cc_autocomplete, #bug_form textarea {
+ width: 100%;
+ }
+[% END %]
+
+[% inline_js = BLOCK %]
+ function onSubmit() {
+ var error = '';
+ if (!isFilledOut('short_desc')) error += 'Please enter a summary.\n';
+ if (!isFilledOut('attachment')) error += 'Please attach the data set/representative sample.\n';
+ if (!isFilledOut('source')) error += 'Please enter the data source.\n';
+ if (!isFilledOut('data_desc')) error += 'Please enter the data description.\n';
+ if (!isFilledOut('release')) error += 'Please enter the parts of data you want released.\n';
+ if (!isFilledOut('why')) error += 'Please enter why you want to release this data.\n';
+ if (!isFilledOut('when')) error += 'Please enter when you would like to release this data.\n';
+
+ if (error) {
+ alert(error);
+ return false;
+ }
+
+ return true;
+ }
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Privacy - Data Release Proposal"
+ style = inline_style
+ style_urls = [ 'skins/standard/enter_bug.css' ]
+ javascript = inline_js
+ javascript_urls = [ 'extensions/BMO/web/js/form_validate.js',
+ 'js/attachment.js', 'js/field.js', 'js/util.js' ]
+ yui = [ 'autocomplete' ]
+%]
+
+<h2>Privacy - Data Release Proposal</h2>
+
+<p>
+ Before filling out this form, please look at the
+ <a href="https://wiki.mozilla.org/Privacy/How_To/Deidentify" target="_blank">guide</a>
+ for releasing info about people.
+</p>
+
+<p>
+ All fields except for CC are required.
+</p>
+
+<form method="post" action="post_bug.cgi" id="bug_form" class="enter_bug_form"
+ enctype="multipart/form-data" onSubmit="return onSubmit()">
+<input type="hidden" name="format" value="privacy-data">
+<input type="hidden" name="product" value="Privacy">
+<input type="hidden" name="component" value="Data Release Proposal">
+<input type="hidden" name="rep_platform" value="All">
+<input type="hidden" name="op_sys" value="Other">
+<input type="hidden" name="priority" value="--">
+<input type="hidden" name="version" value="unspecified">
+<input type="hidden" name="bug_severity" id="bug_severity" value="normal">
+<input type="hidden" name="comment" id="comment" value="">
+<input type="hidden" name="groups" id="groups" value="privacy">
+<input type="hidden" name="token" value="[% token FILTER html %]">
+
+<table>
+
+<tr>
+ <th>
+ <label for="short_desc">Summary:</label>
+ </th>
+ <td>
+ <input type="text" name="short_desc" id="short_desc" value="" size="60">
+ </td>
+</tr>
+
+<tr>
+ <th>
+ <label for="cc">CC:</label>
+ </th>
+ <td>
+ [% INCLUDE global/userselect.html.tmpl
+ id => "cc"
+ name => "cc"
+ value => cc
+ size => 60
+ multiple => 5
+ %]
+ </td>
+ <td>
+ <i>&nbsp;Optional</i>
+ </td>
+</tr>
+
+<tr>
+ <th>
+ <label for="attachment">Data Set:</label>
+ </th>
+ <td>
+ <i>Please attach the data set, or a representative sample.</i>
+ <div>
+ <input type="file" id="attachment" name="data" size="50">
+ <input type="hidden" name="contenttypemethod" value="autodetect">
+ <input type="hidden" name="description" value="Data Set">
+ </div>
+ </td>
+</tr>
+
+<tr>
+ <th>
+ <label for="source">Source:</label>
+ </th>
+ <td>
+ <i>Where does this data come from?</i>
+ <div>
+ <textarea name="source" id="source" rows="5" cols="40"></textarea>
+ </div>
+ </td>
+</tr>
+
+<tr>
+ <th>
+ <label for="data_desc">Data Description:</label>
+ </th>
+ <td>
+ <i>What people and things does this data describe, and what fields does it contain?</i>
+ <div>
+ <textarea name="data_desc" id="data_desc" rows="5" cols="40"></textarea>
+ </div>
+ </td>
+</tr>
+
+<tr>
+ <th>
+ <label for="release">Release:</label>
+ </th>
+ <td>
+ <i>What parts of this data do you want to release?</i>
+ <div>
+ <textarea name="release" id="release" rows="5" cols="40"></textarea>
+ </div>
+ </td>
+</tr>
+
+<tr>
+ <th>
+ <label for="why">Why:</label>
+ </th>
+ <td>
+ <i>Why are we releasing this data, and what do we hope people will do with it?</i>
+ <div>
+ <textarea name="why" id="why" rows="5" cols="40"></textarea>
+ </div>
+ </td>
+</tr>
+
+<tr>
+ <th>
+ <label for="when">Release Time:</label>
+ </th>
+ <td>
+ <i>Is there a particular time by which you would like to release this data?</i>
+ <div>
+ <input type="text" name="when" id="when" value="" size="60">
+ </div>
+ </td>
+</tr>
+
+<tr>
+ <td colspan="2">
+ Expect to discover that you've missed a few of things, so plan for a couple weeks to get them corrected.
+ </td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+ <td>
+ <input type="submit" id="commit" value="Submit Request">
+ </td>
+</tr>
+</table>
+
+</form>
+
+<script type="text/javascript">
+function trySubmit() {
+ var topic = document.getElementById('topic').value;
+ var date = document.getElementById('date').value;
+ var time = document.getElementById('time_hour').value + ':' +
+ document.getElementById('time_minute').value +
+ document.getElementById('ampm').value + " " +
+ document.getElementById('time_zone').value;
+ var location = document.getElementById('location').value;
+ var shortdesc = 'Event - (' + date + ' ' + time + ') - ' + location + ' - ' + topic;
+ document.getElementById('short_desc').value = shortdesc;
+
+ // If intended audience is employees only, add mozilla-employee-confidential group
+ var audience = document.getElementById('audience').value;
+ if (audience == 'Employees Only') {
+ var brownbagRequestForm = document.getElementById('brownbagRequestForm');
+ var groups = document.createElement('input');
+ groups.type = 'hidden';
+ groups.name = 'groups';
+ groups.value = 'mozilla-employee-confidential';
+ brownbagRequestForm.appendChild(groups);
+ }
+
+ return true;
+}
+</script>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-recoverykey.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-recoverykey.html.tmpl
new file mode 100644
index 000000000..ffe9b3482
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-recoverykey.html.tmpl
@@ -0,0 +1,70 @@
+[%# 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 BMO Bugzilla 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):
+ # David Lawrence <dkl@mozilla.com>
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Mozilla Corporation/Foundation Encryption Recovery Key"
+%]
+
+<p>Please complete the following information as you are encrypting your laptop.</p>
+
+<ul>
+ <li>The Recovery Key will be displayed during the encryption process
+ (<a href="https://mana.mozilla.org/wiki/display/INFRASEC/Desktop+Security#DesktopSecurity-DiskencryptionFileVault">more info</a>)
+ </li>
+ <li>The asset tag number is located on a sticker typically on the bottom of the device.</li>
+</ul>
+
+<form method="post" action="post_bug.cgi" id="recoveryKeyForm" enctype="multipart/form-data">
+ <input type="hidden" name="product" value="mozilla.org">
+ <input type="hidden" name="component" value="Server Operations: Desktop Issues">
+ <input type="hidden" name="rep_platform" value="All">
+ <input type="hidden" name="op_sys" value="All">
+ <input type="hidden" name="priority" value="--">
+ <input type="hidden" name="version" value="other">
+ <input type="hidden" name="bug_severity" value="normal">
+ <input type="hidden" name="groups" value="mozilla-employee-confidential">
+ <input type="hidden" name="groups" value="infra">
+ <input type="hidden" name="token" value="[% token FILTER html %]">
+ <input type="hidden" name="cc" value="tfairfield@mozilla.com, ghuerta@mozilla.com">
+ <input type="hidden" name="short_desc" value="Encryption Recovery Key for [% user.name || user.login FILTER html %]">
+ <input type="hidden" name="format" value="recoverykey">
+ <table>
+ <tr>
+ <td align="right"><strong>Recovery Key:</strong></td>
+ <td>
+ <input name="recoverykey" size="60" value="[% recoverykey FILTER html %]">
+ </td>
+ </tr>
+ <tr>
+ <td align="right"><strong>Asset Tag Number:</strong></td>
+ <td>
+ <input name="assettag" size="60" value="[% assettag FILTER html %]">
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td><input type="submit" id="commit" value="Submit"></td>
+ </tr>
+ </table>
+</form>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-swag.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-swag.html.tmpl
new file mode 100644
index 000000000..89f4c8987
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-swag.html.tmpl
@@ -0,0 +1,903 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[%
+items = [
+ { id => '' , name => 'Splendidest Gear' },
+ { id => '#155752' , name => 'Moleskine Notebook' },
+ { id => '#155749' , name => 'Rickshaw Messenger Bag' },
+ { id => '#155415S', name => 'Champion Hooded Sweatshirt S' },
+ { id => '#155415M', name => 'Champion Hooded Sweatshirt M' },
+ { id => '#155415L', name => 'Champion Hooded Sweatshirt L' },
+ { id => '#155415X', name => 'Champion Hooded Sweatshirt XL' },
+ { id => '#1554152', name => 'Champion Hooded Sweatshirt 2XL' },
+ { id => '#157454S', name => 'Very Splendid Package, Men\'s S' },
+ { id => '#157454M', name => 'Very Splendid Package, Men\'s M' },
+ { id => '#157454L', name => 'Very Splendid Package, Men\'s L' },
+ { id => '#157454X', name => 'Very Splendid Package, Men\'s XL' },
+ { id => '#157452S', name => 'Very Splendid Package, Ladies S' },
+ { id => '#157452M', name => 'Very Splendid Package, Ladies M' },
+ { id => '#157452L', name => 'Very Splendid Package, Ladies L' },
+ { id => '#157452X', name => 'Very Splendid Package, Ladies XL' },
+ { id => '#157451S', name => 'Most Splendid Package, S' },
+ { id => '#157451M', name => 'Most Splendid Package, M' },
+ { id => '#157451L', name => 'Most Splendid Package, L' },
+ { id => '#157451X', name => 'Most Splendid Package, XL' },
+ { id => '' , name => 'Splendider' },
+ { id => '#155341M', name => 'Unisex T-shirt Poppy M' },
+ { id => '#155341X', name => 'Unisex T-shirt Poppy XL' },
+ { id => '#1553412', name => 'Unisex T-shirt Poppy 2XL' },
+ { id => '#155344S', name => 'Ladies\' T-shirt Poppy S' },
+ { id => '#155344M', name => 'Ladies\' T-shirt Poppy M' },
+ { id => '#155344L', name => 'Ladies\' T-shirt Poppy L' },
+ { id => '#190928S', name => 'Unisex T-shirt Navy S' },
+ { id => '#190928M', name => 'Unisex T-shirt Navy M' },
+ { id => '#190928L', name => 'Unisex T-shirt Navy L' },
+ { id => '#190928X', name => 'Unisex T-shirt Navy XL' },
+ { id => '#190929L', name => 'Unisex T-shirt Lapis L' },
+ { id => '#1553422', name => 'Unisex T-shirt Navy 2XL' },
+ { id => '#1553423', name => 'Unisex T-shirt Navy 3XL' },
+ { id => '#155413S', name => 'Ladies\' T-shirt Navy S' },
+ { id => '#155413M', name => 'Ladies\' T-shirt Navy M' },
+ { id => '#155413L', name => 'Ladies\' T-shirt Navy L' },
+ { id => '#155413X', name => 'Ladies\' T-shirt Navy XL' },
+ { id => '#155343M', name => 'Unisex T-shirt Lapis M' },
+ { id => '#155343X', name => 'Unisex T-shirt Lapis XL' },
+ { id => '#155414S', name => 'Ladies\' T-shirt Lapis S' },
+ { id => '#155414M', name => 'Ladies\' T-shirt Lapis M' },
+ { id => '#155414L', name => 'Ladies\' T-shirt Lapis L' },
+ { id => '#155339' , name => 'Black Cap with Tote' },
+ { id => '#155340' , name => 'Beanie' },
+ { id => '#155751' , name => 'Drawstring Tote' },
+ { id => '#155758' , name => 'Glossy Finish Ceramic Mug' },
+ { id => '' , name => 'Splendid' },
+ { id => '#155754' , name => 'Mozilla Lanyard with Bulldog Clip' },
+ { id => '#155755' , name => 'Vertical Laminated Badge' },
+ { id => '#155756' , name => 'Silicone Wristband' },
+ { id => '#155757' , name => 'Custom Tattoos - Pkg50' },
+ { id => '#192150' , name => '1.25" Firefox Button-PKG25' },
+ { id => '' , name => 'Firefox OS items' },
+ { id => '#197158' , name => '3" Round Sticker, Firefox logo' },
+ { id => '#185686' , name => '3" Firefox OS Sticker Look Ahead' },
+ { id => '#189674' , name => '3" Firefox OS Mobilizer' },
+ { id => '#187062' , name => 'OS Lanyard w/ Bulldog Clip' },
+ { id => '#180589' , name => 'Sunglasses Firefox OS' },
+ { id => '#180595' , name => 'Rubber Grip Pens Firefox OS' },
+ { id => '#180593' , name => 'Firefox OS Moleskine Notebook' },
+]
+
+mozspaces = [
+ {
+ name => 'Beijing',
+ address1 => 'Mozilla Online Ltd, International Club Office Tower 800A',
+ address2 => '21 Jian Guo Men Wai Avenue',
+ city => 'Beijing',
+ state => 'Chaoyang District',
+ country => 'China',
+ postcode => '100020',
+ },
+ {
+ name => 'Berlin',
+ address1 => 'MZ Denmark ApS - Germany',
+ address2 => 'Rungestrasse 22 - 24',
+ city => 'Berlin',
+ state => 'Germany',
+ country => 'Germany',
+ postcode => '10179',
+ },
+ {
+ name => 'London',
+ address1 => 'Mozilla London',
+ address2 => '101 St. Martin\'s Lane, 3rd Floor',
+ city => 'London',
+ state => 'Greater London',
+ country => 'UK',
+ postcode => 'WC2N 4AZ',
+ },
+ {
+ name => 'Mountain View',
+ address1 => 'Mozilla',
+ address2 => '650 Castro St., Suite 300',
+ city => 'Mountain View',
+ state => 'CA',
+ country => 'USA',
+ postcode => '94041-2072',
+ },
+ {
+ name => 'Paris',
+ address1 => 'Mozilla',
+ address2 => '16 bis Boulevard Montmartre',
+ city => 'Paris',
+ state => 'Paris',
+ country => 'France',
+ postcode => '75009',
+ },
+ {
+ name => 'Portland',
+ address1 => 'Mozilla Portland',
+ address2 => 'Brewery Block 2, 1120 NW Couch St. Suite 320',
+ city => 'Portland',
+ state => 'OR',
+ country => 'USA',
+ postcode => '97209',
+ },
+ {
+ name => 'San Francisco',
+ address1 => 'Mozilla',
+ address2 => '2 Harrison Street, Suite 175',
+ city => 'San Francisco',
+ state => 'CA',
+ country => 'USA',
+ postcode => '94105',
+ },
+ {
+ name => 'Taipei',
+ address1 => '4F-A1, No. 106, Sec.5, Xinyi Rd',
+ address2 => '',
+ city => 'Taipei City',
+ state => 'Xinyi District',
+ country => 'Taiwan',
+ postcode => '11047',
+ },
+ {
+ name => 'Tokyo',
+ address1 => '7-5-6 Roppongi',
+ address2 => '',
+ city => 'Minato-ku',
+ state => 'Tokyo',
+ country => 'Japan',
+ postcode => '106-0032',
+ },
+ {
+ name => 'Toronto',
+ address1 => 'Mozilla Canada',
+ address2 => '366 Adelaide Street W, Suite 500',
+ city => 'Toronto',
+ state => 'Ontario',
+ country => 'Canada',
+ postcode => 'M5V 1R9',
+ },
+ {
+ name => 'Vancouver',
+ address1 => 'Mozilla Canada',
+ address2 => '163 West Hastings Street, Suite 209',
+ city => 'Vancouver',
+ state => 'BC',
+ country => 'Canada',
+ postcode => 'V6B 1H5',
+ },
+]
+
+cost_centers = [
+ 'Accounting (1210)',
+ 'Add Ons (7500)',
+ 'Advanced Techology Lab (6400)',
+ 'Brand Engagement (2400)',
+ 'Business Affairs (1100)',
+ 'Business Development (1150)',
+ 'Business Development Programs (7700)',
+ 'Business Support Services (1000)',
+ 'Cloud & Services (3000)',
+ 'Community Engagement (2300)',
+ 'Design (4400)',
+ 'Dev Infra (3130)',
+ 'Engagement (2000)',
+ 'Engineering Platform (8000)',
+ 'Engineering Program Management (8300)',
+ 'Facilities (1250)',
+ 'Finance Planning & Analysis (1211)',
+ 'Firefox (5000)',
+ 'Firefox Android Engineering (5310)',
+ 'Firefox Android Product Management (5330)',
+ 'Firefox Android UX (5320)',
+ 'Firefox Desktop (5200)',
+ 'Firefox Desktop Engineering (5210)',
+ 'Firefox Desktop Platform Integration (5240)',
+ 'Firefox Desktop Product Management (5230)',
+ 'Firefox Desktop UX (5220)',
+ 'Firefox Dev Tools (5400)',
+ 'Firefox Mobile (5300)',
+ 'Firefox OS Engineering I (6110)',
+ 'Firefox OS Engineering II (6120)',
+ 'Firefox OS Product Management (6200)',
+ 'Firefox OS UX (6300)',
+ 'Identity Eng (3210)',
+ 'Identity Infra (3110)',
+ 'Infrastructure (servers) (3100)',
+ 'Insights and Strategy (4000)',
+ 'IT & Network (1400)',
+ 'Labs (7600)',
+ 'Legal (1120)',
+ 'Localization (L10n) (5100)',
+ 'Location Engineering (3230)',
+ 'Location Infra (3150)',
+ 'Marketplace (7000)',
+ 'Marketplace Apps Engineering (7110)',
+ 'Marketplace Bus. Development (7400)',
+ 'Marketplace Engineering / AMO (7120)',
+ 'Marketplace Engineering /Dev Ecosystem (7130)',
+ 'Marketplace Product Management (7200)',
+ 'Marketplace UX (7300)',
+ 'Market Strategy (4200)',
+ 'Metrics (4300)',
+ 'Misc Infra (3160)',
+ 'Mobile (6000)',
+ 'Mobile Business Development (1130)',
+ 'Mobile Engineering (6130)',
+ 'Operations (3600)',
+ 'People (1340)',
+ 'People Ops (1320)',
+ 'Platform Accessibility (8490)',
+ 'Platform Content (8440)',
+ 'Platform Integration (8480)',
+ 'Platform Network (8410)',
+ 'Platform Network & Security (8400)',
+ 'Platform Performance (8470)',
+ 'Platform Rendering & Media (8450)',
+ 'Platform Security (8420)',
+ 'Platform Security Assurance (8430)',
+ 'Platform Stability & Plugin (8460)',
+ 'PR (2200)',
+ 'Product Marketing (2100)',
+ 'QA (8500)',
+ 'QA Android (8550)',
+ 'QA Automation (8520)',
+ 'QA Firefox Desktop (8510)',
+ 'QA FirefoxOS (8560)',
+ 'QA Mobile (8540)',
+ 'QA Services (8570)',
+ 'QA Web (8530)',
+ 'Release Engineering (8100)',
+ 'Release Management (5010)',
+ 'Research (6900)',
+ 'Services Engineering (3200)',
+ 'Services Product Management (3400)',
+ 'Services UX (3300)',
+ 'SUMO (2600)',
+ 'Sync Engineering (3220)',
+ 'Sync Infra (3120)',
+ 'UP (5500)',
+ 'User Research (4100)',
+ 'Web Engineering (8200)',
+ 'WebRTC (1160)',
+ 'WebRTC Infra (3140)',
+ 'Web Security and Security Automation (3500)',
+ 'Websites & Developer Engagement (2500)',
+]
+
+%]
+
+[% inline_style = BLOCK %]
+#gear_form th {
+ text-align: right;
+ font-weight: normal;
+}
+
+#gear_form .heading {
+ text-align: left;
+ font-weight: bold;
+ border-top: 2px dotted #969696;
+}
+
+.mandatory {
+ color: red;
+}
+[% END %]
+
+[% inline_javascript = BLOCK %]
+var Dom = YAHOO.util.Dom;
+var needed = {
+[% FOREACH item = items %]
+ [% NEXT UNLESS item.id %]
+ '[% item.id FILTER js %]': 0[% ',' UNLESS loop.last %]
+[% END %]
+};
+var needed_freeform = [];
+
+var gear = [
+[% FOREACH item = items %]
+ { id: '[% item.id FILTER js %]', name: '[% item.name FILTER js %]' }
+ [% ',' UNLESS loop.last %]
+[% END %]
+];
+
+var mozspaces = {
+[% FOREACH space = mozspaces %]
+ '[% space.name FILTER js %]': {
+ [% FOREACH key = space.keys.sort %]
+ '[% key FILTER js %]': '[% space.$key FILTER js %]'[% ',' UNLESS loop.last %]
+ [% END %]
+ }[% ',' UNLESS loop.last %]
+[% END %]
+};
+
+[%# implemented this way to allow for dynamic updating of mandatory fields #%]
+var fields = [
+ { id: 'firstname', mandatory: true },
+ { id: 'lastname', mandatory: true },
+ { id: 'email', mandatory: true },
+ { id: 'mozspace', mandatory: false },
+ { id: 'teamcode', mandatory: true },
+ { id: 'purpose', mandatory: true },
+ { id: 'purpose_other', mandatory: false },
+ { id: 'date_required', mandatory: false },
+ { id: 'items', mandatory: true },
+ { id: 'shiptofirstname', mandatory: true },
+ { id: 'shiptolastname', mandatory: true },
+ { id: 'shiptoemail', mandatory: true },
+ { id: 'shiptoaddress1', mandatory: true },
+ { id: 'shiptoaddress2', mandatory: false },
+ { id: 'shiptocity', mandatory: true },
+ { id: 'shiptostate', mandatory: true },
+ { id: 'shiptocountry', mandatory: true },
+ { id: 'shiptopostcode', mandatory: true },
+ { id: 'shiptophone', mandatory: true },
+ { id: 'shiptoidrut', mandatory: false },
+ { id: 'comment', mandatory: false }
+];
+
+function initFields() {
+ [%# find fields in the form, and update the fields array #%]
+ var rows = Dom.get('gear_form').getElementsByTagName('TR');
+ for (var i = 0, l = rows.length; i < l; i++) {
+ var row = rows[i];
+ var field = firstChild(row, 'INPUT') || firstChild(row, 'SELECT') || firstChild(row, 'TEXTAREA');
+ if (!field || field.type == 'submit') continue;
+ var id = field.id;
+ var label = firstChild(row, 'TH');
+ for (var j = 0, m = fields.length; j < m; j++) {
+ if (fields[j].id == id) {
+ fields[j].field = field;
+ fields[j].label = label;
+ fields[j].caption = label.textContent;
+ break;
+ }
+ }
+ }
+ createCalendar('date_required');
+}
+
+function tagMandatoryFields() {
+ [%# add or remove the "* mandatory" marker from fields #%]
+ for (var i = 0, l = fields.length; i < l; i++) {
+ var f = fields[i];
+ if (!f.label) continue;
+ var caption = f.caption;
+ if (f.mandatory)
+ caption = caption + '&nbsp;<span class="mandatory">*</span>';
+ f.label.innerHTML = caption;
+ }
+}
+
+function validateAndSubmit() {
+ var alert_text = '';
+ for(var i = 0, l = fields.length; i < l; i++) {
+ var f = fields[i];
+ if (f.mandatory && !isFilledOut(f.id))
+ if (f.field.nodeName == 'SELECT') {
+ alert_text += 'Please select the ' + f.caption + ".\n";
+ } else {
+ alert_text += 'Please enter the ' + f.caption + ".\n";
+ }
+ }
+ if (isFilledOut('email') && !isValidEmail(Dom.get('email').value))
+ alert_text += "Please enter a valid Email Address.\n";
+ if (isFilledOut('shiptoemail') && !isValidEmail(Dom.get('shiptoemail').value))
+ alert_text += "Please enter a valid Shipping Email Address.\n";
+
+ if (alert_text != '') {
+ alert(alert_text);
+ return false;
+ }
+
+ Dom.get('short_desc').value = 'Mozilla Gear - ' + Dom.get('firstname').value + ' ' + Dom.get('lastname').value;
+ return true;
+}
+
+function onPurposeChange() {
+ var value = Dom.get('purpose').value;
+ var other = Dom.get('purpose_other');
+
+ if (value == 'Event') {
+ getField('purpose_other').mandatory = true;
+ other.placeholder = 'link to wiki'
+ Dom.removeClass('purpose_other_row', 'bz_default_hidden');
+ Dom.addClass('recognition_row', 'bz_default_hidden');
+
+ } else if (value == 'Gear Space Stock') {
+ getField('purpose_other').mandatory = true;
+ other.placeholder = 'indicate space'
+ Dom.removeClass('purpose_other_row', 'bz_default_hidden');
+ Dom.addClass('recognition_row', 'bz_default_hidden');
+
+ } else if (value == 'Other') {
+ getField('purpose_other').mandatory = true;
+ other.placeholder = 'more information';
+ Dom.removeClass('purpose_other_row', 'bz_default_hidden');
+ Dom.addClass('recognition_row', 'bz_default_hidden');
+
+ } else if (value == 'Mozillian Recognition') {
+ getField('purpose_other').mandatory = false;
+ Dom.addClass('purpose_other_row', 'bz_default_hidden');
+ Dom.removeClass('recognition_row', 'bz_default_hidden');
+ onRecognitionChange();
+
+ } else {
+ getField('purpose_other').mandatory = false;
+ Dom.addClass('purpose_other_row', 'bz_default_hidden');
+ Dom.addClass('recognition_row', 'bz_default_hidden');
+ }
+
+ onRecognitionChange();
+}
+
+function onRecognitionChange() {
+ var mandatory = Dom.get('purpose').value != 'Mozillian Recognition'
+ || !Dom.get('recognition_shipping').checked;
+ getField('shiptoaddress1').mandatory = mandatory;
+ getField('shiptocity').mandatory = mandatory;
+ getField('shiptostate').mandatory = mandatory;
+ getField('shiptocountry').mandatory = mandatory;
+ getField('shiptopostcode').mandatory = mandatory;
+ getField('shiptophone').mandatory = mandatory;
+ tagMandatoryFields();
+}
+
+function onMozSpaceChange() {
+ if (Dom.get('mozspace').value) {
+ Dom.removeClass('shipto_mozspace_container', 'bz_default_hidden');
+ } else {
+ Dom.addClass('shipto_mozspace_container', 'bz_default_hidden');
+ }
+ onShipToMozSpaceClick();
+}
+
+function onShipToMozSpaceClick() {
+ var address1 = address2 = city = state = country = postcode = '';
+ if (Dom.get('shipto_mozspace').checked) {
+ var space = Dom.get('mozspace').value;
+ address1 = mozspaces[space].address1;
+ address2 = mozspaces[space].address2;
+ city = mozspaces[space].city;
+ state = mozspaces[space].state;
+ country = mozspaces[space].country;
+ postcode = mozspaces[space].postcode;
+ }
+ Dom.get('shiptoaddress1').value = address1;
+ Dom.get('shiptoaddress2').value = address2;
+ Dom.get('shiptocity').value = city;
+ Dom.get('shiptostate').value = state;
+ Dom.get('shiptocountry').value = country;
+ Dom.get('shiptopostcode').value = postcode;
+ Dom.get('shiptophone').value = '';
+ Dom.get('shiptoidrut').value = '';
+ onRecognitionChange();
+}
+
+function onAddGearChange(focusInput) {
+ var add_gear = Dom.get('add_gear').value;
+ var isFreeform = add_gear == 'custom' || add_gear == 'other';
+ if (isFreeform) {
+ Dom.addClass('quantity', 'bz_default_hidden');
+ resetFreeform();
+ Dom.get('freeform_quantity').value = Dom.get('quantity').value;
+ Dom.removeClass('freeform_quantity', 'bz_default_hidden');
+ Dom.removeClass('add_freeform', 'bz_default_hidden');
+ if (focusInput)
+ Dom.get('freeform_add').focus();
+ } else {
+ Dom.get('quantity').value = Dom.get('freeform_quantity').value;
+ Dom.removeClass('quantity', 'bz_default_hidden');
+ Dom.addClass('freeform_quantity', 'bz_default_hidden');
+ Dom.addClass('add_freeform', 'bz_default_hidden');
+ }
+}
+
+function firstChild(parent, name) {
+ var a = parent.getElementsByTagName(name);
+ return a.length == 0 ? false : a[0];
+}
+
+function getField(id) {
+ for(var i = 0, l = fields.length; i < l; i++) {
+ if (fields[i].id == id)
+ return fields[i];
+ }
+ return false;
+}
+
+function addGear() {
+ var id = Dom.get('add_gear').value;
+ if (id == 'custom' || id == 'other') {
+ var quantity = parseInt(Dom.get('freeform_quantity').value, 10);
+ var name = Dom.get('freeform_add').value;
+ if (!quantity || !name) return;
+ needed_freeform.push({ 'type': id, 'quantity': quantity, 'name': name });
+ Dom.get('add_gear').value = '';
+ resetFreeform();
+ onAddGearChange();
+ } else {
+ var quantity = parseInt(Dom.get('quantity').value, 10);
+ if (!quantity || !id) return;
+ needed[id] += quantity;
+ }
+ showGear();
+}
+
+function resetFreeform() {
+ Dom.get('freeform_quantity').value = '1';
+ Dom.get('freeform_add').value = '';
+}
+
+function removeGear(id) {
+ if (!id) return;
+ needed[id] = 0;
+ showGear();
+}
+
+function removeFreeform(index) {
+ needed_freeform.splice(index, 1);
+ showGear();
+}
+
+function showGear() {
+ var html = '<table border="0" cellpadding="2" cellspacing="0">';
+ var text = '';
+ var count = 0;
+ for (var i = 0, l = gear.length; i < l; i++) {
+ var item = gear[i];
+ var id = item.id;
+ if (!id) continue;
+ if (!needed[id]) continue;
+ count += needed[id];
+ html += '<tr>' +
+ '<td>' + needed[id] + ' x&nbsp;</td>' +
+ '<td>' + YAHOO.lang.escapeHTML(item.name) + '</td>' +
+ '<td><button onclick="removeGear(\'' + id + '\');return false">Remove</button></td>' +
+ '</tr>';
+ text += needed[id] + ' x ' + id + ' ' + item.name + "\n";
+ }
+ for (var i = 0, l = needed_freeform.length; i < l; i++) {
+ var item = needed_freeform[i];
+ count += item.quantity;
+ html += '<tr>' +
+ '<td>' + item.quantity + ' x&nbsp;</td>' +
+ '<td>(' + item.type + ') ' + YAHOO.lang.escapeHTML(item.name) + '</td>' +
+ '<td><button onclick="removeFreeform(\'' + i + '\');return false">Remove</button></td>' +
+ '</tr>';
+ text += item.quantity + ' x (' + item.type + ') ' + item.name + "\n";
+ }
+ if (!count)
+ html += '<tr><td><i>No gear selected.</i></td></tr>';
+ html += '</table>';
+ Dom.get('gear_container').innerHTML = html;
+ Dom.get('items').value = text;
+}
+
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Mozilla Gear"
+ style = inline_style
+ javascript = inline_javascript
+ javascript_urls = [ 'extensions/BMO/web/js/form_validate.js',
+ 'js/field.js', 'js/util.js' ]
+ yui = [ 'autocomplete', 'calendar' ]
+%]
+
+<h1>Mozilla Gear</h1>
+
+<p>
+ Want gear? Follow the steps below and click Submit Request.
+</p>
+<p>
+ Requests are reviewed and processed on Monday morning (US/Pacific). Any
+ requests received after 9am Monday will be processed the following week.
+</p>
+<ul>
+ <li>
+ If approved, your request will either be sent to our gear partner, Staples,
+ for shipment or it will be available for pick-up from your Mozilla space.
+ </li>
+ <li>
+ If your request is not approved, we will let you know why or possibly ask
+ for more information.
+ </li>
+</ul>
+
+<p>
+ Check <a href="https://wiki.mozilla.org/GearStore" target="_blank">the gear
+ wiki</a> for more information about gear, including approved uses and the
+ list of available gear.
+</p>
+
+<p>
+ Gear requests for Rep-driven events and campaigns should continue to be
+ submitted through <a href="https://wiki.mozilla.org/ReMo/Tools_and_Resources"
+ target="_blank">their existing process</a>.
+</p>
+
+<form method="post" action="post_bug.cgi" id="swagRequestForm" enctype="multipart/form-data"
+ onSubmit="return validateAndSubmit();">
+ <input type="hidden" name="format" value="swag">
+ <input type="hidden" name="product" value="Marketing">
+ <input type="hidden" name="component" value="Swag Requests">
+ <input type="hidden" name="rep_platform" value="All">
+ <input type="hidden" name="op_sys" value="Other">
+ <input type="hidden" name="priority" value="--">
+ <input type="hidden" name="version" value="unspecified">
+ <input type="hidden" name="bug_severity" id="bug_severity" value="normal">
+ <input type="hidden" name="short_desc" id="short_desc" value="">
+ <input type="hidden" name="groups" value="mozilla-engagement">
+ <input type="hidden" name="token" value="[% token FILTER html %]">
+
+<table id="gear_form">
+
+<tr>
+ <td>&nbsp;</td>
+</tr>
+<tr>
+ <th class="heading" colspan="2">Tell Us What You Want</th>
+</tr>
+
+<tr>
+ <th>Purpose of Gear</th>
+ <td>
+ <select name="purpose" id="purpose" onchange="onPurposeChange()">
+ <option value="">Please select..</option>
+ <option value="Campaign">Campaign</option>
+ <option value="Event">Event</option>
+ <option value="Gear Space Stock">Gear Space Stock</option>
+ <option value="Mozillian Recognition">Mozillian Recognition</option>
+ <option value="Onboarding">Onboarding</option>
+ <option value="Press">Press</option>
+ <option value="Recruiting">Recruiting</option>
+ <option value="VIP">VIP</option>
+ <option value="Other">Other</option>
+ </select>
+ </td>
+</tr>
+
+<tr id="purpose_other_row" class="bz_default_hidden">
+ <th>Purpose Text</th>
+ <td>
+ <input name="purpose_other" id="purpose_other" size="50">
+ </td>
+</tr>
+
+<tr id="recognition_row" class="bz_default_hidden">
+ <th>&nbsp;</th>
+ <td>
+ <input type="checkbox" name="recognition_shipping" id="recognition_shipping" value="Yes"
+ onclick="onRecognitionChange()">
+ <label for="recognition_shipping">
+ This [% terms.bug %] needs recipient shipping information
+ </label><br>
+ <input type="checkbox" name="recognition_sizing" id="recognition_sizing" value="Yes">
+ <label for="recognition_sizing">
+ This [% terms.bug %] needs recipient size information
+ </label><br>
+ </td>
+</tr>
+
+<tr>
+ <th>Date Required</th>
+ <td>
+ <input name="date_required" id="date_required" size="25"
+ onchange="updateCalendarFromField(this)">
+ <button type="button" class="calendar_button" id="button_calendar_date_required"
+ onclick="showCalendar('date_required')"><span>cal</span></button>
+ <div id="con_calendar_date_required"></div>
+ </td>
+</tr>
+
+<tr>
+ <th>Gear Needed</th>
+ <td>
+ <input type="hidden" name="items" id="items" value="">
+ <a href="https://wiki.mozilla.org/GearStore/Gearavailable" target="_blank">
+ View the current inventory</a>, then add your selection(s):<br>
+
+ <input type="text" size="2" id="quantity" value="1"
+ onblur="this.value = parseInt(this.value, 10) ? Math.floor(parseInt(this.value, 10)) : 1">
+ <select id="add_gear" onChange="onAddGearChange(true)">
+ <option value="">Please select..</option>
+ [% first_group = 1 %]
+ [% FOREACH item = items %]
+ [% IF item.id == "" %]
+ [% "</optgroup>" UNLESS first_group %]
+ [% first_group = 0 %]
+ <optgroup label="[% item.name FILTER html %]">
+ [% ELSE %]
+ <option value="[% item.id FILTER html %]">[% item.name FILTER html %]</option>
+ [% END %]
+ [% END %]
+ [% "</optgroup>" UNLESS first_group %]
+ <optgroup label="otherwise">
+ <option value="custom">custom</option>
+ <option value="other">other</option>
+ </optgroup>
+ </select>
+ <span id="add_freeform" class="bz_default_hidden">
+ <br>
+ Tell us how many and what you are looking for here. Add details in the
+ comments field below.
+ <br>
+ <input type="text" size="2" id="freeform_quantity" value="1"
+ onblur="this.value = parseInt(this.value, 10) ? Math.floor(parseInt(this.value, 10)) : 1">
+ <input type="text" id="freeform_add" size="40">
+ </span>
+ <button onclick="addGear();return false">Add</button>
+ <br>
+
+ <div id="gear_container"></div>
+ </td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+</tr>
+<tr>
+ <th class="heading" colspan="2">Tell Us About You</th>
+</tr>
+
+<tr>
+ <th>First Name</th>
+ <td><input name="firstname" id="firstname" size="50" maxlength="30"></td>
+</tr>
+
+<tr>
+ <th>Last Name</th>
+ <td><input name="lastname" id="lastname" size="50" maxlength="30"></td>
+</tr>
+
+<tr>
+ <th>Email Address</th>
+ <td><input name="email" id="email" size="50" maxlength="50"></td>
+</tr>
+
+<tr>
+ <th>My Mozilla Space</th>
+ <td>
+ <select name="mozspace" id="mozspace" onchange="onMozSpaceChange()">
+ <option value="">Please select..</option>
+ [% FOREACH space = mozspaces %]
+ <option value="[% space.name FILTER html %]">[% space.name FILTER html %]</option>
+ [% END %]
+ </select>
+ <i>(if applicable)</i>
+ <div id="shipto_mozspace_container" class="bz_default_hidden">
+ <input type="checkbox" id="shipto_mozspace" onclick="onShipToMozSpaceClick()">
+ <label for="shipto_mozspace">Ship to this address</label>
+ </div>
+</tr>
+
+<tr>
+ <th>Team + Department Code</th>
+ <td>
+ <select name="teamcode" id="teamcode">
+ <option value="">Please select..</option>
+ [% FOREACH cost IN cost_centers %]
+ <option value="[% cost FILTER html %]">[% cost FILTER html %]</option>
+ [% END %]
+ </select>
+ </td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+</tr>
+<tr>
+ <th class="heading" colspan="2">Tell Us Where To Send It</th>
+</tr>
+
+<tr>
+ <td colspan="2">
+ Please be aware that shipping can cost as much as, if not more than, your
+ item. And, items shipped internationally incur customs fees that can be
+ 100%+ the cost of the package. When possible, requests will be filled from
+ gear at your Mozilla space.
+ </td>
+</tr>
+
+<tr>
+ <th>First Name</th>
+ <td><input name="shiptofirstname" id="shiptofirstname" size="50" maxlength="50"></td>
+</tr>
+<tr>
+ <th>Last Name</th>
+ <td><input name="shiptolastname" id="shiptolastname" size="50" maxlength="50"></td>
+</tr>
+<tr>
+ <th>Email Address</th>
+ <td><input name="shiptoemail" id="shiptoemail" size="50" maxlength="50"></td>
+</tr>
+<tr>
+ <th>Address</th>
+ <td><input name="shiptoaddress1" id="shiptoaddress1" size="50" maxlength="50"></td>
+</tr>
+<tr>
+ <th>Address 2</th>
+ <td><input name="shiptoaddress2" id="shiptoaddress2" size="50" maxlength="50"></td>
+</tr>
+<tr>
+ <th>City</th>
+ <td><input name="shiptocity" id="shiptocity" size="50" maxlength="50"></td>
+</tr>
+<tr>
+ <th>State</th>
+ <td><input name="shiptostate" id="shiptostate" size="50" maxlength="50"></td>
+</tr>
+<tr>
+ <th>Country</th>
+ <td><input name="shiptocountry" id="shiptocountry" size="50" maxlength="50"></td>
+</tr>
+<tr>
+ <th>Postal Code</th>
+ <td><input name="shiptopostcode" id="shiptopostcode" size="50" maxlength="50"></td>
+</tr>
+<tr>
+ <th>Recipient Telephone</th>
+ <td>
+ <input name="shiptophone" id="shiptophone" size="50" maxlength="50">
+ <i>(include country code if outside of the US)</i>
+ </td>
+</tr>
+<tr>
+ <th>Personal ID/RUT</th>
+ <td>
+ <input name="shiptoidrut" id="shiptoidrut" size="50" maxlength="50">
+ <i>(if your country requires this)</i>
+ </td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+</tr>
+<tr>
+ <th class="heading" colspan="2">Tell Us Anything Else</th>
+</tr>
+
+<tr>
+ <th>Additional Comments</th>
+ <td><textarea id="comment" name="comment" rows="5" cols="50"></textarea></td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+ <td><input type="submit" id="commit" value="Submit Request"></td>
+</tr>
+
+</table>
+</form>
+
+<p>
+ <span class="mandatory">*</span> Required Field
+</p>
+
+<p>
+ Requests will only be visible to the person who submitted it, authorized
+ members of the Mozilla Engagement team, and our Staples Customer Service rep.
+ We do this to help protect the personal identifying information in this [% terms.bugs %].
+</p>
+
+<script>
+ initFields();
+ onPurposeChange();
+ onAddGearChange();
+ tagMandatoryFields();
+ showGear();
+</script>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-trademark.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-trademark.html.tmpl
new file mode 100644
index 000000000..977ad00d4
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-trademark.html.tmpl
@@ -0,0 +1,87 @@
+[%# 1.0@bugzilla.org %]
+[%# 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 <gerv@gerv.net>
+ # Ville Skyttä <ville.skytta@iki.fi>
+ # John Hoogstrate <hoogstrate@zeelandnet.nl>
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Trademark Usage Requests"
+%]
+
+[% USE Bugzilla %]
+
+<p>
+ If, after reading
+ <a href="http://www.mozilla.org/foundation/trademarks/">the trademark policy
+ documents</a>, you know you need permission to use a certain trademark, this
+ is the place to be.
+</p>
+
+<p><strong>Please use this form for trademark requests only!</strong></p>
+
+<form method="post" action="post_bug.cgi" id="tmRequestForm">
+
+ <input type="hidden" name="product" value="Marketing">
+ <input type="hidden" name="component" value="Trademark Permissions">
+ <input type="hidden" name="bug_severity" value="enhancement">
+ <input type="hidden" name="rep_platform" value="All">
+ <input type="hidden" name="priority" value="P3">
+ <input type="hidden" name="op_sys" value="Other">
+ <input type="hidden" name="version" value="unspecified">
+ <input type="hidden" name="groups" value="marketing-private">
+ <input type="hidden" name="token" value="[% token FILTER html %]">
+
+ <table>
+ <tr>
+ <td align="right"><strong>Summary:</strong></td>
+ <td colspan="3">
+ <input name="short_desc" size="60" value="[% short_desc FILTER html %]">
+ </td>
+ </tr>
+
+ <tr><td align="right" valign="top"><strong>Description:</strong></td>
+ <td colspan="3">
+ <textarea name="comment" rows="10" cols="80">
+ [% comment FILTER html %]</textarea>
+ <br>
+ </td>
+ </tr>
+ <tr>
+ <td align="right"><strong>URL&nbsp;(optional):</strong></td>
+ <td colspan="3">
+ <input name="bug_file_loc" size="60"
+ value="[% bug_file_loc FILTER html %]">
+ </td>
+ </tr>
+ </table>
+
+ <br>
+
+ <input type="submit" id="commit" value="Submit Request">
+</form>
+
+<p>Thanks for contacting us.
+ You will be notified by email of any progress made in resolving your
+ request.
+</p>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-user-engagement.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-user-engagement.html.tmpl
new file mode 100644
index 000000000..f523b205b
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-user-engagement.html.tmpl
@@ -0,0 +1,219 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% inline_style = BLOCK %]
+#engagement_form {
+ padding: 10px;
+}
+#engagement_form .required:after {
+ content: " *";
+ color: red;
+}
+#engagement_form .field_label {
+ font-weight: bold;
+}
+#engagement_form .field_desc {
+ padding-bottom: 3px;
+}
+#engagement_form .field_desc,
+#engagement_form .head_desc {
+ width: 600px;
+ word-wrap: normal;
+}
+#engagement_form .head_desc {
+ padding-top: 5px;
+ padding-bottom: 12px;
+}
+#engagement_form .form_section {
+ margin-bottom: 10px;
+}
+#engagement_form textarea {
+ font-family: inherit;
+ font-size: inherit;
+}
+#engagement_form em {
+ font-size: 1em;
+}
+.yui-calcontainer {
+ z-index: 2;
+}
+[% END %]
+
+[% inline_javascript = BLOCK %]
+function validateAndSubmit() {
+ var alert_text = '';
+ if (!isFilledOut('goals')) alert_text += 'Please enter a value for project goals.\n';
+ if (!isFilledOut('short_desc')) alert_text += 'Please enter a value for project title.\n';
+ if (!isFilledOut('audience')) alert_text += 'Please enter a value for who you are trying to reach.\n';
+ if (!isFilledOut('timing_date')) alert_text += 'Please enter a value for project timing.\n';
+ if (!isFilledOut('localization')) alert_text += 'Please enter a value for project localization.\n';
+ if (!isFilledOut('success')) alert_text += 'Please enter a value for project success\n';
+ if (!isFilledOut('bug_file_loc')) alert_text += 'Please enter a value for project destination url.\n';
+ if (!isFilledOut('mozilla_goal')) alert_text += 'Please enter a value for Mozilla goal.\n';
+ if (alert_text != '') {
+ alert(alert_text);
+ return false;
+ }
+ return true;
+}
+function toggleGoalOther() {
+ var goal_select = YAHOO.util.Dom.get('goal');
+ if (goal_select.options[goal_select.selectedIndex].value == 'Other') {
+ YAHOO.util.Dom.removeClass('goal_other','bz_default_hidden');
+ }
+ else {
+ YAHOO.util.Dom.addClass('goal_other','bz_default_hidden');
+ }
+}
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = "User Engagement Form"
+ style = inline_style
+ javascript = inline_javascript
+ javascript_urls = [ 'extensions/BMO/web/js/form_validate.js',
+ 'js/field.js', 'js/util.js' ]
+ yui = [ "autocomplete", "calendar" ]
+%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+
+<form id="engagement_form" method="post" action="post_bug.cgi" enctype="multipart/form-data"
+ onSubmit="return validateAndSubmit();">
+ <input type="hidden" name="format" value="user-engagement">
+ <input type="hidden" name="product" value="Marketing">
+ <input type="hidden" name="component" value="User Engagement">
+ <input type="hidden" name="rep_platform" value="All">
+ <input type="hidden" name="op_sys" value="Other">
+ <input type="hidden" name="version" value="unspecified">
+ <input type="hidden" name="bug_severity" id="bug_severity" value="normal">
+ <input type="hidden" name="token" value="[% token FILTER html %]">
+
+<img title="User Engagement Form" src="extensions/BMO/web/images/user-engagement.png">
+
+<div class="head_desc">
+ Have something that you think our users should know about? Is there a campaign that you
+ think may benefit from promotion on Mozilla’s User Engagement channels?<br>
+ <br>
+ Please use this form to help us understand the goals of your project or campaign.
+ We’ll use this data to recommend a promotional plan that will meet your needs.
+</div>
+
+<div class="form_section">
+ <label for="short_desc" class="field_label required">Project / Request Title</label>
+ <div class="field_desc">
+ Please tell us about your request in a few words
+ </div>
+ <input type="text" name="short_desc" id="short_desc" size="80">
+</div>
+
+<div class="form_section">
+ <label for="goals" class="field_label required">Project Goals</label>
+ <div class="field_desc">
+ Here’s where you tell us all the juicy details, especially your GOALS for this project.
+ Please tell us “I want to achieve this awesome goal†(ie. increase sign ups for this initiative,
+ get 1 million users to do X, etc.) rather than “I want a promotion on this specific channel.â€
+ </div>
+ <textarea id="goals" name="goals" cols="80" rows="5"></textarea>
+</div>
+
+<div class="form_section">
+ <label for="audience" class="field_label required">Who are you trying to reach?</label>
+ <div class="field_desc">
+ Use this section to explain the type of user you’re targeting. Who is the audience? Consumers?
+ Early adopters? Developers? Be specific.
+ </div>
+ <textarea id="audience" name="audience" cols="80" rows="5"></textarea>
+</div>
+
+<div class="form_section">
+ <label for="localization" class="field_label required">Localization</label>
+ <div class="field_desc">
+ Please tell us if your content needs to be localized, and in what languages.
+ Is the landing page localized?
+ </div>
+ <input type="text" name="localization" id="localization" size="80">
+</div>
+
+<div class="form_section">
+ <label for="bug_file_loc" class="field_label required">Destination URL</label>
+ <div class="field_desc">
+ Where would the user be sent when they click on the promotion?
+ </div>
+ <input type="text" name="bug_file_loc" id="bug_file_loc" size="80">
+</div>
+
+<div class="form_section">
+ <label for="timing_date" class="field_label required">Timing</label>
+ <div class="field_desc">
+ Here’s where you tell us when the initiative will launch. The content calendar
+ is determined at least 6 weeks in advance (to accommodate localization, etc.)
+ so the more notice we have, the better we’ll be able to help you meet your goals.
+ </div>
+ <input name="timing_date" size="20" id="timing_date" value=""
+ onchange="updateCalendarFromField(this)">
+ <button type="button" class="calendar_button"
+ id="button_calendar_timing_date"
+ onclick="showCalendar('timing_date')">
+ <span>Calendar</span>
+ </button>
+ <div id="con_calendar_timing_date"></div>
+ <script type="text/javascript">
+ createCalendar('timing_date')
+ </script>
+</div>
+
+<div class="form_section">
+ <label for="success" class="field_label required">Success</label>
+ <div class="field_desc">
+ In a few words, tell us how you will define success from promotion to our consumers?
+ (example: Success is 1000 people clicking on this link.)
+ </div>
+ <textarea id="success" name="success" cols="80" rows="5"></textarea>
+</div>
+
+<div class="form_section">
+ <label for="mozilla_goal" class="field_label required">Mozilla Goal</label>
+ <div class="field_desc">
+ What high-level Mozilla goal does this achieve?
+ </div>
+ <input type="text" name="mozilla_goal" id="mozilla_goal" size="80">
+</div>
+
+<div class="form_section">
+ <label for="cc" class="field_label">Points of Contact</label>
+ <div class="field_desc">
+ Who should be cc’d on this [% terms.bug %] and kept informed of updates?
+ </div>
+ [% INCLUDE global/userselect.html.tmpl
+ id => "cc"
+ name => "cc"
+ value => ""
+ size => 80
+ classes => ["bz_userfield"]
+ multiple => 5
+ %]
+</div>
+
+<div class="head_desc">
+ Once your form has been submitted, a tracking [% terms.bug %] will be created. We will
+ then reach out for additional info and next steps. Thanks!
+</div>
+
+<input type="submit" id="commit" value="Submit">
+
+<p>
+ [ <span class="required_star">*</span> <span class="required_explanation">Required Field</span> ]
+</p>
+
+</form>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-web-bounty.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-web-bounty.html.tmpl
new file mode 100644
index 000000000..d76d57298
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-web-bounty.html.tmpl
@@ -0,0 +1,142 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% inline_style = BLOCK %]
+#web_bounty_form {
+ padding: 10px;
+}
+#web_bounty_form .required:after {
+ content: " *";
+ color: red;
+}
+#web_bounty_form .field_label {
+ font-weight: bold;
+}
+#web_bounty_form .field_desc {
+ padding-bottom: 3px;
+}
+#web_bounty_form .field_desc,
+#web_bounty_form .head_desc {
+ width: 600px;
+ word-wrap: normal;
+}
+#web_bounty_form .head_desc {
+ padding-top: 5px;
+ padding-bottom: 12px;
+}
+#web_bounty_form .form_section {
+ margin-bottom: 10px;
+}
+#web_bounty_form textarea {
+ font-family: inherit;
+ font-size: inherit;
+ margin: 0 !important;
+}
+#web_bounty_form em {
+ font-size: 1em;
+}
+[% END %]
+
+[% inline_javascript = BLOCK %]
+function validateAndSubmit() {
+ var alert_text = '';
+ if (!isFilledOut('short_desc')) alert_text += 'Please enter a value for summary.\n';
+ if (!isFilledOut('comment')) alert_text += 'Please enter a value for comment.\n';
+ if (alert_text != '') {
+ alert(alert_text);
+ return false;
+ }
+ return true;
+}
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Web Bounty Form"
+ style = inline_style
+ javascript = inline_javascript
+ javascript_urls = [ 'extensions/BMO/web/js/form_validate.js',
+ 'js/field.js', 'js/util.js' ]
+%]
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+
+<form id="web_bounty_form" method="post" action="post_bug.cgi" enctype="multipart/form-data"
+ onSubmit="return validateAndSubmit();">
+ <input type="hidden" name="product" value="Websites">
+ <input type="hidden" name="component" value="Other">
+ <input type="hidden" name="rep_platform" value="All">
+ <input type="hidden" name="op_sys" value="All">
+ <input type="hidden" name="version" value="unspecified">
+ <input type="hidden" name="bug_severity" id="bug_severity" value="normal">
+ <input type="hidden" name="priority" id="priority" value="--">
+ <input type="hidden" name="target_milestone" id="target_milestone" value="---">
+ <input type="hidden" name="status_whiteboard" id="status_whiteboard" value="[reporter-external] [web-bounty-form] [verif?]">
+ <input type="hidden" name="bug_severity" id="bug_severity" value="normal">
+ <input type="hidden" name="groups" id="group_52" value="websites-security">
+ <input type="hidden" name="flag_type-803" id="flag_type-803" value="?">
+ <input type="hidden" name="token" value="[% token FILTER html %]">
+
+<div class="head_desc">
+ <a href="https://developer.mozilla.org/en-US/docs/Mozilla/QA/Bug_writing_guidelines?redirectlocale=en-US&redirectslug=Bug_writing_guidelines">
+ [% terms.Bug %] writing guidelines</a>
+</div>
+
+<div class="form_section">
+ <label for="short_desc" class="field_label required">Summary / Title</label>
+ <div class="field_desc">
+ A short description of the issue being reported including the host name
+ for the website on which it exists (example xss in blarg.foo.mozilla.org)
+ </div>
+ <input type="text" name="short_desc" id="short_desc" size="80">
+</div>
+
+<div class="form_section">
+ <label for="comment" class="field_label required">Comment</label>
+ <div class="field_desc">
+ How was this issue discovered, include the steps, tools or other information that
+ will help reproduce and diagnose the issue. A good primer on what to include can
+ be found <a href="https://developer.mozilla.org/en-US/docs/Mozilla/QA">here</a>.
+ </div>
+ <textarea id="comment" name="comment" cols="80" rows="5"></textarea>
+</div>
+
+<div class="form_section">
+ <label for="bug_file_loc" class="field_label">URL</label>
+ <div class="field_desc">
+ The full URL (hostname/subpage) where the issue exists (if the URL is especially long
+ please just include it in the comments)
+ </div>
+ <input type="text" name="bug_file_loc" id="bug_file_loc" size="80">
+</div>
+
+<div class="form_section">
+ <label for="data" class="field_label">Attachment</label>
+ <div class="field_desc">
+ A file that can add context to the report, such as a screen shot or code block for
+ reproduction purposes.
+ </div>
+ <input type="file" id="data" name="data" size="50">
+ <input type="hidden" name="contenttypemethod" value="autodetect" />
+ <div class="field_desc">
+ <label for="description">Description</label>
+ </div>
+ <input type="text" id="description" name="description" size="80">
+</div>
+
+<input type="submit" id="commit" value="Submit">
+
+<p>
+ [ <span class="required_star">*</span> <span class="required_explanation">Required Field</span> ]
+</p>
+
+</form>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/create-winqual.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-winqual.html.tmpl
new file mode 100644
index 000000000..fd21ed4ed
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/create-winqual.html.tmpl
@@ -0,0 +1,831 @@
+[%# 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 <gerv@gerv.net>
+ # Ville Skyttä <ville.skytta@iki.fi>
+ # Shane H. W. Travis <travis@sedsystems.ca>
+ # Marc Schumann <wurblzap@gmail.com>
+ # Akamai Technologies <bugzilla-dev@akamai.com>
+ # Max Kanat-Alexander <mkanat@bugzilla.org>
+ # Frédéric Buclin <LpSolit@gmail.com>
+ #%]
+
+[% PROCESS "global/field-descs.none.tmpl" %]
+
+[% title = BLOCK %]Enter [% terms.Bug %]: [% product.name FILTER html %][% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = title
+ yui = [ 'autocomplete', 'calendar', 'datatable', 'button' ]
+ style_urls = [ 'skins/standard/attachment.css',
+ 'skins/standard/enter_bug.css',
+ 'skins/custom/create_bug.css' ]
+ javascript_urls = [ "js/attachment.js", "js/util.js",
+ "js/field.js", "js/TUI.js", "js/bug.js",
+ "js/create_bug.js" ]
+ onload = "init();"
+%]
+
+<script type="text/javascript">
+<!--
+
+function init() {
+ set_assign_to();
+ hideElementById('attachment_true');
+ showElementById('attachment_false');
+ showElementById('btn_no_attachment');
+ initCrashSignatureField();
+ init_take_handler('[% user.login FILTER js %]');
+}
+
+function initCrashSignatureField() {
+ var el = document.getElementById('cf_crash_signature');
+ if (!el) return;
+ [% IF cf_crash_signature.length %]
+ YAHOO.util.Dom.addClass('cf_crash_signature_container', 'bz_default_hidden');
+ [% ELSE %]
+ hideEditableField('cf_crash_signature_container','cf_crash_signature_input',
+ 'cf_crash_signature_action', 'cf_crash_signature');
+ [% END %]
+}
+
+var initialowners = new Array();
+var last_initialowner;
+var initialccs = new Array();
+var components = new Array();
+var comp_desc = new Array();
+var flags = new Array();
+[% IF Param("useqacontact") %]
+ var initialqacontacts = new Array([% product.components.size %]);
+ var last_initialqacontact;
+[% END %]
+[% count = 0 %]
+[%- FOREACH c = product.components %]
+ [% NEXT IF NOT c.is_active %]
+ [% NEXT IF c.name != 'WinQual Reports' %]
+ components[[% count %]] = "[% c.name FILTER js %]";
+ comp_desc[[% count %]] = "[% c.description FILTER html_light FILTER js %]";
+ initialowners[[% count %]] = "[% c.default_assignee.login FILTER js %]";
+ [% flag_list = [] %]
+ [% FOREACH f = c.flag_types(is_active=>1).bug %]
+ [% flag_list.push(f.id) %]
+ [% END %]
+ [% FOREACH f = c.flag_types(is_active=>1).attachment %]
+ [% flag_list.push(f.id) %]
+ [% END %]
+ flags[[% count %]] = [[% flag_list.join(",") FILTER js %]];
+ [% IF Param("useqacontact") %]
+ initialqacontacts[[% count %]] = "[% c.default_qa_contact.login FILTER js %]";
+ [% END %]
+
+ [% SET initial_cc_list = [] %]
+ [% FOREACH cc_user = c.initial_cc %]
+ [% initial_cc_list.push(cc_user.login) %]
+ [% END %]
+ initialccs[[% count %]] = "[% initial_cc_list.join(', ') FILTER js %]";
+
+ [% count = count + 1 %]
+[%- END %]
+
+function set_assign_to() {
+ // Based on the selected component, fill the "Assign To:" field
+ // with the default component owner, and the "QA Contact:" field
+ // with the default QA Contact. It also selectively enables flags.
+ var form = document.Create;
+ var assigned_to = form.assigned_to.value;
+
+[% IF Param("useqacontact") %]
+ var qa_contact = form.qa_contact.value;
+[% END %]
+
+ var index = -1;
+ if (form.component.type == 'select-one') {
+ index = form.component.selectedIndex;
+ } else if (form.component.type == 'hidden') {
+ // Assume there is only one component in the list
+ index = 0;
+ }
+ if (index != -1) {
+ var owner = initialowners[index];
+ var component = components[index];
+ if (assigned_to == last_initialowner
+ || assigned_to == owner
+ || assigned_to == '') {
+ form.assigned_to.value = owner;
+ last_initialowner = owner;
+ }
+
+ document.getElementById('initial_cc').innerHTML = initialccs[index];
+ document.getElementById('comp_desc').innerHTML = comp_desc[index];
+
+ if (initialccs[index]) {
+ showElementById('initial_cc_label');
+ showElementById('initial_cc');
+ } else {
+ hideElementById('initial_cc_label');
+ hideElementById('initial_cc');
+ }
+
+ [% IF Param("useqacontact") %]
+ var contact = initialqacontacts[index];
+ if (qa_contact == last_initialqacontact
+ || qa_contact == contact
+ || qa_contact == '') {
+ form.qa_contact.value = contact;
+ last_initialqacontact = contact;
+ }
+ [% END %]
+
+ // First, we disable all flags. Then we re-enable those
+ // which are available for the selected component.
+ var inputElements = document.getElementsByTagName("select");
+ var inputElement, flagField;
+ for ( var i=0 ; i<inputElements.length ; i++ ) {
+ inputElement = inputElements.item(i);
+ if (inputElement.name.search(/^flag_type-(\d+)$/) != -1) {
+ var id = inputElement.name.replace(/^flag_type-(\d+)$/, "$1");
+ inputElement.disabled = true;
+ // Also hide the requestee field, if it exists.
+ inputElement = document.getElementById("requestee_type-" + id);
+ if (inputElement)
+ YAHOO.util.Dom.addClass(inputElement.parentNode, 'bz_default_hidden');
+ }
+ }
+ // Now enable flags available for the selected component.
+ for (var i = 0; i < flags[index].length; i++) {
+ flagField = document.getElementById("flag_type-" + flags[index][i]);
+ // Do not enable flags the user cannot set nor request.
+ if (flagField && flagField.options.length > 1) {
+ flagField.disabled = false;
+ // Re-enabling the requestee field depends on the status
+ // of the flag.
+ toggleRequesteeField(flagField, 1);
+ }
+ }
+ }
+}
+
+var status_comment_required = new Array();
+[% FOREACH status = bug_status %]
+ status_comment_required['[% status.name FILTER js %]'] =
+ [% status.comment_required_on_change_from() ? 'true' : 'false' %]
+[% END %]
+
+TUI_alternates['expert_fields'] = 'Show Advanced Fields';
+// Hide the Advanced Fields by default, unless the user has a cookie
+// that specifies otherwise.
+TUI_hide_default('expert_fields');
+
+-->
+</script>
+
+<form name="Create" id="Create" method="post" action="post_bug.cgi"
+ class="enter_bug_form" enctype="multipart/form-data"
+ onsubmit="return validateEnterBug(this)">
+ <input type="hidden" name="product" value="Firefox">
+ <input type="hidden" name="component" value="WinQual Reports">
+ <input type="hidden" name="token" value="[% token FILTER html %]">
+ <input type="hidden" name="groups" value="winqual-data">
+
+<table>
+<tbody>
+ <tr>
+ <td colspan="4">
+ [%# Migration note: The following file corresponds to the old Param
+ # 'entryheaderhtml'
+ #%]
+ [% PROCESS 'bug/create/user-message.html.tmpl' %]
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <input type="button" id="expert_fields_controller"
+ value="Hide Advanced Fields" onClick="toggleAdvancedFields()">
+ [%# Show the link if the browser supports JS %]
+ <script type="text/javascript">
+ YAHOO.util.Dom.removeClass('expert_fields_controller',
+ 'bz_default_hidden');
+ </script>
+ </td>
+ <td colspan="2">
+ (<span class="required_star">*</span> =
+ <span class="required_explanation">Required Field</span>)
+ </td>
+ </tr>
+
+ <tr>
+ [% INCLUDE bug/field.html.tmpl
+ bug = default, field = bug_fields.product, editable = 0,
+ value = product.name %]
+ [% INCLUDE bug/field.html.tmpl
+ bug = default, field = bug_fields.reporter, editable = 0,
+ value = user.login %]
+ </tr>
+
+ [%# We can't use the select block in these two cases for various reasons. %]
+ <tr>
+ [% component_desc_url = BLOCK -%]
+ describecomponents.cgi?product=[% product.name FILTER uri %]
+ [% END %]
+ [% INCLUDE "bug/field-label.html.tmpl"
+ field = bug_fields.component editable = 1
+ desc_url = component_desc_url
+ %]
+ <td id="field_container_component">
+ [% INCLUDE bug/field.html.tmpl
+ bug = default, field = bug_fields.component, editable = 0,
+ value = "WinQual Reports", no_tds = 1 %]
+ <script type="text/javascript">
+ <!--
+ [%+ INCLUDE "bug/field-events.js.tmpl"
+ field = bug_fields.component %]
+ YAHOO.util.Event.onDOMReady(set_assign_to);
+ //-->
+ </script>
+ </td>
+
+ <td colspan="2" id="comp_desc_container">
+ [%# Enclose the fieldset in a nested table so that its width changes based
+ # on the length on the component description. %]
+ <table>
+ <tr>
+ <td>
+ <fieldset>
+ <legend>Component Description</legend>
+ <div id="comp_desc" class="comment"></div>
+ </fieldset>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ [% INCLUDE "bug/field-label.html.tmpl"
+ field = bug_fields.version editable = 1 rowspan = 3
+ %]
+ <td rowspan="3">
+ <select name="version" id="version" size="5">
+ [%- FOREACH v = version %]
+ [% NEXT IF NOT v.is_active %]
+ <option value="[% v.name FILTER html %]"
+ [% ' selected="selected"' IF v.name == default.version %]>[% v.name FILTER html -%]
+ </option>
+ [%- END %]
+ </select>
+ </td>
+
+ [% INCLUDE bug/field.html.tmpl
+ bug = default, field = bug_fields.bug_severity, editable = 1,
+ value = default.bug_severity %]
+ </tr>
+
+ <tr>
+ [% INCLUDE bug/field.html.tmpl
+ bug = default, field = bug_fields.rep_platform, editable = 1,
+ value = default.rep_platform %]
+ </tr>
+
+ <tr>
+ [% INCLUDE bug/field.html.tmpl
+ bug = default, field = bug_fields.op_sys, editable = 1,
+ value = default.op_sys %]
+ </tr>
+ [% IF !Param('defaultplatform') || !Param('defaultopsys') %]
+ <tr>
+ <th colspan="3">&nbsp;</th>
+ <td id="os_guess_note" class="comment">
+ <div>We've made a guess at your
+ [% IF Param('defaultplatform') %]
+ operating system. Please check it
+ [% ELSIF Param('defaultopsys') %]
+ platform. Please check it
+ [% ELSE %]
+ operating system and platform. Please check them
+ [% END %]
+ and make any corrections if necessary.</div>
+ </td>
+ </tr>
+ [% END %]
+</tbody>
+
+<tbody class="expert_fields">
+ <tr>
+ [% IF Param('usetargetmilestone') && Param('letsubmitterchoosemilestone') %]
+ [% INCLUDE select field = bug_fields.target_milestone %]
+ [% ELSE %]
+ <td colspan="2">&nbsp;</td>
+ [% END %]
+
+ [% IF Param('letsubmitterchoosepriority') %]
+ [% INCLUDE bug/field.html.tmpl
+ bug = default, field = bug_fields.priority, editable = 1,
+ value = default.priority %]
+ [% ELSE %]
+ <td colspan="2">&nbsp;</td>
+ [% END %]
+ </tr>
+</tbody>
+
+<tbody class="expert_fields">
+ <tr>
+ <td colspan="4">&nbsp;</td>
+ </tr>
+
+ <tr>
+ [% INCLUDE bug/field.html.tmpl
+ bug = default, field = bug_fields.bug_status,
+ editable = (bug_status.size > 1), value = default.bug_status
+ override_legal_values = bug_status %]
+ </tr>
+
+ <tr>
+ [% INCLUDE "bug/field-label.html.tmpl"
+ field = bug_fields.assigned_to editable = 1
+ %]
+ <td>
+ [% INCLUDE global/userselect.html.tmpl
+ id => "assigned_to"
+ name => "assigned_to"
+ value => assigned_to
+ disabled => assigned_to_disabled
+ size => 30
+ emptyok => 1
+ custom_userlist => assignees_list
+ %]
+ [% UNLESS assigned_to_disabled %]
+ <span id="take_bug">
+ &nbsp;(<a title="Assign to yourself" href="#"
+ onclick="return take_bug('[% user.login FILTER js %]')">take</a>)
+ </span>
+ [% END %]
+ <noscript>(Leave blank to assign to component's default assignee)</noscript>
+ </td>
+
+[% IF Param("useqacontact") %]
+ [% INCLUDE "bug/field-label.html.tmpl"
+ field = bug_fields.qa_contact editable = 1
+ %]
+ <td>
+ [% INCLUDE global/userselect.html.tmpl
+ id => "qa_contact"
+ name => "qa_contact"
+ value => qa_contact
+ disabled => qa_contact_disabled
+ size => 30
+ emptyok => 1
+ custom_userlist => qa_contacts_list
+ %]
+ <noscript>(Leave blank to assign to default qa contact)</noscript>
+ </td>
+ </tr>
+[% END %]
+
+ <tr>
+ [% INCLUDE "bug/field-label.html.tmpl"
+ field = bug_fields.cc editable = 1
+ %]
+ <td>
+ [% INCLUDE global/userselect.html.tmpl
+ id => "cc"
+ name => "cc"
+ value => cc
+ disabled => cc_disabled
+ size => 30
+ multiple => 5
+ %]
+ </td>
+ <th>
+ <span id="initial_cc_label" class="bz_default_hidden">
+ Default [% field_descs.cc FILTER html %]:
+ </span>
+ </th>
+ <td>
+ <span id="initial_cc"></span>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="3">&nbsp;</td>
+ </tr>
+
+[% IF Param("usebugaliases") %]
+ <tr>
+ [% INCLUDE "bug/field-label.html.tmpl"
+ field = bug_fields.alias editable = 1
+ %]
+ <td colspan="2">
+ <input name="alias" size="20" value="[% alias FILTER html %]">
+ </td>
+ </tr>
+[% END %]
+</tbody>
+
+<tbody>
+ <tr>
+ [% INCLUDE "bug/field-label.html.tmpl"
+ field = bug_fields.short_desc editable = 1
+ %]
+ <td colspan="3" class="field_value">
+ <input name="short_desc" size="70" value="[% short_desc FILTER html %]"
+ maxlength="255" spellcheck="true" aria-required="true"
+ class="required text_input" id="short_desc">
+ </td>
+ </tr>
+
+ [% IF feature_enabled('jsonrpc') AND !cloned_bug_id %]
+ <tr id="possible_duplicates_container" class="bz_default_hidden">
+ <th>Possible<br>Duplicates:</th>
+ <td colspan="3">
+ <div id="possible_duplicates"></div>
+ <script type="text/javascript">
+ var dt_columns = [
+ { key: "id", label: "[% field_descs.bug_id FILTER js %]",
+ formatter: YAHOO.bugzilla.dupTable.formatBugLink },
+ { key: "summary",
+ label: "[% field_descs.short_desc FILTER js %]",
+ formatter: "text" },
+ { key: "status",
+ label: "[% field_descs.bug_status FILTER js %]",
+ formatter: YAHOO.bugzilla.dupTable.formatStatus },
+ { key: "update_token", label: '',
+ formatter: YAHOO.bugzilla.dupTable.formatCcButton }
+ ];
+ YAHOO.bugzilla.dupTable.addCcMessage = "Add Me to the CC List";
+ YAHOO.bugzilla.dupTable.init({
+ container: 'possible_duplicates',
+ columns: dt_columns,
+ product_name: '[% product.name FILTER js %]',
+ summary_field: 'short_desc',
+ options: {
+ MSG_LOADING: 'Searching for possible duplicates...',
+ MSG_EMPTY: 'No possible duplicates found.',
+ SUMMARY: 'Possible Duplicates'
+ }
+ });
+ </script>
+ </td>
+ </tr>
+ [% END %]
+
+ <tr>
+ <th>Description:</th>
+ <td colspan="3">
+
+ [% defaultcontent = BLOCK %]
+ [% IF cloned_bug_id %]
++++ This [% terms.bug %] was initially created as a clone of [% terms.Bug %] #[% cloned_bug_id FILTER html %] +++
+
+
+ [% END %]
+ [%-# We are within a BLOCK. The comment will be correctly HTML-escaped
+ # by global/textarea.html.tmpl. So we must not escape the comment here. %]
+ [% comment FILTER none %]
+ [%- END %]
+ [% INCLUDE global/textarea.html.tmpl
+ name = 'comment'
+ id = 'comment'
+ minrows = 10
+ maxrows = 25
+ cols = constants.COMMENT_COLS
+ defaultcontent = defaultcontent
+ %]
+ <br>
+ </td>
+ </tr>
+
+<tbody class="expert_fields">
+ <tr>
+ [% INCLUDE "bug/field-label.html.tmpl"
+ field = bug_fields.bug_file_loc editable = 1
+ %]
+ <td colspan="3" class="field_value">
+ <input name="bug_file_loc" id="bug_file_loc" class="text_input"
+ size="40" value="[% bug_file_loc FILTER html %]">
+ </td>
+ </tr>
+</tbody>
+
+<tbody>
+ [% IF Param("maxattachmentsize") %]
+ <tr>
+ <th>Attachment:</th>
+ <td colspan="3">
+ <div id="attachment_false" class="bz_default_hidden">
+ <input type="button" value="Add an attachment" onClick="handleWantsAttachment(true)">
+ </div>
+
+ <div id="attachment_true">
+ <input type="button" id="btn_no_attachment" value="Don't add an attachment"
+ class="bz_default_hidden" onClick="handleWantsAttachment(false)">
+ <fieldset>
+ <legend>Add an attachment</legend>
+ <table class="attachment_entry">
+ [% PROCESS attachment/createformcontents.html.tmpl
+ flag_types = product.flag_types(is_active=>1).attachment
+ any_flags_requesteeble = 1
+ flag_table_id ="attachment_flags" %]
+ </table>
+
+ [% IF user.is_insider %]
+ <input type="checkbox" id="comment_is_private" name="comment_is_private"
+ [% ' checked="checked"' IF comment_is_private %]
+ onClick="updateCommentTagControl(this, 'comment')">
+ <label for="comment_is_private">
+ Make this attachment and [% terms.bug %] description private (visible only
+ to members of the <strong>[% Param('insidergroup') FILTER html %]</strong> group)
+ </label>
+ [% END %]
+ </fieldset>
+ </div>
+ </td>
+ </tr>
+ [% END %]
+</tbody>
+
+<tbody class="expert_fields">
+ [% IF user.in_group('editbugs', product.id) %]
+ <tr>
+ [% INCLUDE "bug/field-label.html.tmpl"
+ field = bug_fields.dependson editable = 1
+ %]
+ <td>
+ <input name="dependson" accesskey="d" value="[% dependson FILTER html %]" size="30">
+ </td>
+ [% INCLUDE "bug/field-label.html.tmpl"
+ field = bug_fields.blocked editable = 1
+ %]
+ <td>
+ <input name="blocked" accesskey="b" value="[% blocked FILTER html %]" size="30">
+ </td>
+ </tr>
+
+ [% IF use_keywords %]
+ <tr>
+ [% INCLUDE bug/field.html.tmpl
+ bug = default, field = bug_fields.keywords, editable = 1,
+ value = keywords, desc_url = "describekeywords.cgi",
+ value_span = 3
+ %]
+ </tr>
+ [% END %]
+
+ <tr>
+ <th>Status Whiteboard:</th>
+ <td colspan="3" class="field_value">
+ <input id="status_whiteboard" name="status_whiteboard" size="70"
+ value="[% status_whiteboard FILTER html %]" class="text_input">
+ </td>
+ </tr>
+ [% END %]
+
+ [% IF user.is_timetracker %]
+ <tr>
+ [% INCLUDE "bug/field-label.html.tmpl"
+ field = bug_fields.estimated_time editable = 1
+ %]
+ <td>
+ <input name="estimated_time" size="6" maxlength="6" value="[% estimated_time FILTER html %]">
+ </td>
+ [% INCLUDE bug/field.html.tmpl
+ bug = default, field = bug_fields.deadline, value = deadline, editable = 1
+ %]
+ </tr>
+ [% END %]
+</tbody>
+
+<tbody>
+[%# non-tracking flags custom fields %]
+[% FOREACH field = Bugzilla.active_custom_fields(product=>product,type=>1) %]
+ [% NEXT IF field.type == constants.FIELD_TYPE_EXTENSION %]
+ [% NEXT UNLESS field.enter_bug %]
+ [%# crash-signature gets custom handling %]
+ [% IF field.name == 'cf_crash_signature' %]
+ [% show_crash_signature = 1 %]
+ [% NEXT %]
+ [% END %]
+ [% SET value = ${field.name}.defined ? ${field.name} : "" %]
+ <tr [% 'class="expert_fields"' IF !field.is_mandatory %]>
+ [% INCLUDE bug/field.html.tmpl
+ bug = default, field = field, value = value, editable = 1,
+ value_span = 3 %]
+ </tr>
+[% END %]
+</tbody>
+
+[%# crash-signature handling %]
+[% IF show_crash_signature %]
+<tbody class="expert_fields">
+ <tr>
+ <th id="field_label_cf_crash_signature" class="field_label">
+ <label for="cf_crash_signature"> Crash Signature: </label>
+ </th>
+ <td colspan="3">
+ <span id="cf_crash_signature_container">
+ <span id="cf_crash_signature_nonedit_display"><i>None</i></span>
+ (<a id="cf_crash_signature_action" href="#">edit</a>)
+ </span>
+ <span id="cf_crash_signature_input">
+ <textarea id="cf_crash_signature" name="cf_crash_signature" rows="4" cols="60"
+ >[% cf_crash_signature FILTER html %]</textarea>
+ </span>
+ </td>
+ </tr>
+</tbody>
+[% END %]
+
+[% old_tracking_flags = [] %]
+[% old_project_flags = [] %]
+[% FOREACH field = Bugzilla.active_custom_fields(product=>product,type=>2) %]
+ [% NEXT IF field.type == constants.FIELD_TYPE_EXTENSION %]
+ [% NEXT UNLESS field.enter_bug %]
+ [% IF cf_is_project_flag(field.name) %]
+ [% old_project_flags.push(field) %]
+ [% ELSE %]
+ [% old_tracking_flags.push(field) %]
+ [% END %]
+[% END %]
+
+[% display_flags = 0 %]
+[% any_flags_requesteeble = 0 %]
+[% FOREACH flag_type = product.flag_types.bug %]
+ [% display_flags = 1 %]
+ [% SET any_flags_requesteeble = 1 IF flag_type.is_requestable && flag_type.is_requesteeble %]
+ [% LAST IF display_flags && any_flags_requesteeable %]
+[% END %]
+
+[% IF old_project_flags.size || old_tracking_flags.size || display_flags %]
+ <tbody class="expert_fields">
+ <tr>
+ <th>Flags:</th>
+ <td colspan="3">
+ <div id="bug_flags_false" class="bz_default_hidden">
+ <input type="button" value="Set [% terms.bug FILTER html %] flags" onClick="handleWantsBugFlags(true)">
+ </div>
+
+ <div id="bug_flags_true">
+ <input type="button" id="btn_no_bug_flags" value="Don't set [% terms.bug %] flags"
+ class="bz_default_hidden" onClick="handleWantsBugFlags(false)">
+
+ <fieldset>
+ <legend>Set [% terms.bug %] flags</legend>
+
+ <table cellpadding="0" cellspacing="0">
+ <tr>
+ [% IF old_tracking_flags.size %]
+ <td [% IF project_flags.size %]rowspan="2"[% END %]>
+ <table class="tracking_flags">
+ <tr>
+ <th colspan="2" style="text-align:left">Tracking Flags:</th>
+ </tr>
+ [% FOREACH field = old_tracking_flags %]
+ [% SET value = ${field.name}.defined ? ${field.name} : "" %]
+ <tr>
+ [% INCLUDE bug/field.html.tmpl
+ bug = default
+ field = field
+ value = value
+ editable = 1
+ value_span = 3
+ %]
+ </tr>
+ [% END %]
+ [% Hook.process('tracking_flags_end') %]
+ </table>
+ </td>
+ [% END %]
+ [% IF old_project_flags.size %]
+ <td>
+ <table class="tracking_flags">
+ <tr>
+ <th colspan="2" style="text-align:left">Project Flags:</th>
+ </tr>
+ [% FOREACH field = old_project_flags %]
+ [% SET value = ${field.name}.defined ? ${field.name} : "" %]
+ <tr>
+ [% INCLUDE bug/field.html.tmpl
+ bug = default
+ field = field
+ value = value
+ editable = 1
+ value_span = 3
+ %]
+ </tr>
+ [% END %]
+ [% Hook.process('project_flags_end') %]
+ </table>
+ </td>
+ </tr>
+ <tr>
+ [% END %]
+ [% IF display_flags %]
+ <td>
+ [% PROCESS "flag/list.html.tmpl" flag_types = product.flag_types.bug
+ any_flags_requesteeble = any_flags_requesteeble
+ flag_table_id = "bug_flags"
+ %]
+ </td>
+ [% END %]
+ </tr>
+ [% Hook.process('bug_flags_end') %]
+ </table>
+ </fieldset>
+ </div>
+ </td>
+ </tr>
+ </tbody>
+[% END %]
+
+<tbody>
+ [%# Form controls for entering additional data about the bug being created. %]
+ [% Hook.process("form") %]
+
+ <tr>
+ <th>&nbsp;</th>
+ <td colspan="3">
+ <input type="submit" id="commit" value="Submit [% terms.Bug %]">
+ &nbsp;&nbsp;&nbsp;&nbsp;
+ <input type="submit" name="maketemplate" id="maketemplate"
+ value="Remember values as bookmarkable template"
+ onclick="bz_no_validate_enter_bug=true" class="expert_fields">
+ </td>
+ </tr>
+</tbody>
+ [%# "status whiteboard" and "qa contact" are the longest labels
+ # add them here to avoid shifting the page when toggling advanced fields %]
+ <tr>
+ <th class="hidden_text">Status Whiteboard:</th>
+ <td>&nbsp;</td>
+ <th class="hidden_text">QA Contact:</th>
+ </tr>
+ </table>
+ <input type="hidden" name="form_name" value="enter_bug">
+</form>
+
+[%# Links or content with more information about the bug being created. %]
+[% Hook.process("end") %]
+
+<div id="guided">
+ <a id="guided_img" href="enter_bug.cgi?format=guided&amp;product=[% product.name FILTER uri %]"><img
+ src="extensions/BMO/web/images/guided.png" width="16" height="16" border="0" align="absmiddle"></a>
+ <a id="guided_link" href="enter_bug.cgi?format=guided&amp;product=[% product.name FILTER uri %]"
+ >Switch to the [% terms.Bugzilla %] Helper</a>
+</div>
+
+[% PROCESS global/footer.html.tmpl %]
+
+[%############################################################################%]
+[%# Block for SELECT fields #%]
+[%############################################################################%]
+
+[% BLOCK select %]
+
+ [% INCLUDE "bug/field-label.html.tmpl"
+ field = field editable = 1
+ %]
+ <td>
+ <select name="[% field.name FILTER html %]"
+ id="[% field.name FILTER html %]">
+ [%- FOREACH x = ${field.name} %]
+ [% NEXT IF NOT x.is_active %]
+ <option value="[% x.name FILTER html %]"
+ [% " selected=\"selected\"" IF x.name == default.${field.name} %]>
+ [% display_value(field.name, x.name) FILTER html %]
+ </option>
+ [% END %]
+ </select>
+ </td>
+[% END %]
+
+[% BLOCK build_userlist %]
+ [% user_found = 0 %]
+ [% default_login = default_user.login %]
+ [% RETURN UNLESS default_login %]
+
+ [% FOREACH user = userlist %]
+ [% IF user.login == default_login %]
+ [% user_found = 1 %]
+ [% LAST %]
+ [% END %]
+ [% END %]
+
+ [% userlist.push({login => default_login,
+ identity => default_user.identity,
+ visible => 1})
+ UNLESS user_found %]
+[% END %]
diff --git a/extensions/BMO/template/en/default/bug/create/created-fxos-betaprogram.html.tmpl b/extensions/BMO/template/en/default/bug/create/created-fxos-betaprogram.html.tmpl
new file mode 100644
index 000000000..145c976cd
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/created-fxos-betaprogram.html.tmpl
@@ -0,0 +1,30 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Firefox OS Beta Bug Submission"
+%]
+
+<h1>Thank you!</h1>
+
+<p>
+ Thank you for submitting feedback about Firefox OS.
+</p>
+
+<p>
+ We'll link any [% terms.bugs %] we file (or are already filed) as a result of
+ this feedback to this report so you can be notified about their progress.
+</p>
+
+<p style="font-size: x-small">
+ Reference: <a href="show_bug.cgi?id=[% id FILTER uri %]">#[% id FILTER html %]</a>
+</p>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/bug/create/custom_forms.none.tmpl b/extensions/BMO/template/en/default/bug/create/custom_forms.none.tmpl
new file mode 100644
index 000000000..25af4fa47
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/custom_forms.none.tmpl
@@ -0,0 +1,173 @@
+[%# 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.
+ #%]
+
+[%# link => url (can be relative to bugzilla.mozilla.org, or full url)
+ # title => visible title
+ # group => optional group name, if present the form won't be show to
+ # users not in this group
+ # hide => optional boolean, if true the form will not be shown on
+ # enter_bug (but will be visible on the custom forms list)
+ #%]
+
+[%
+custom_forms = {
+ "mozilla.org" => [
+ {
+ link => "form.moz.project.review",
+ title => "Mozilla Project Review",
+ group => "mozilla-employee-confidential",
+ },
+ {
+ link => "form.trademark",
+ title => "Trademark Usage Requests",
+ },
+ {
+ link => "form.gear",
+ title => "Mozilla Gear Request",
+ group => "mozilla-employee-confidential",
+ },
+ {
+ link => "form.poweredby",
+ title => "Powered by Mozilla Logo Requests",
+ },
+ {
+ link => "form.mozlist",
+ title => "Mozilla Discussion Forum Requests",
+ group => "mozilla-employee-confidential",
+ },
+ ],
+ "Marketing" => [
+ {
+ link => "form.user.engagement",
+ title => "User Engagement Initiation Form",
+ group => "mozilla-employee-confidential",
+ },
+ {
+ link => "form.gear",
+ title => "Mozilla Gear Request",
+ group => "mozilla-employee-confidential",
+ },
+ {
+ link => "form.creative",
+ title => "Brand Engagement Initiation Form",
+ group => "mozilla-employee-confidential",
+ },
+ {
+ link => "form.poweredby",
+ title => "Powered by Mozilla Logo Requests",
+ },
+ ],
+ "Finance" => [
+ {
+ link => "form.finance",
+ title => "Finance Request",
+ group => "mozilla-employee-confidential",
+ },
+ ],
+ "Privacy" => [
+ {
+ link => "form.privacy.data",
+ title => "Privacy - Data Release Proposal",
+ group => "mozilla-employee-confidential",
+ },
+ ],
+ "Mozilla PR" => [
+ {
+ link => "form.mozpr",
+ title => "PR Project Form",
+ group => "pr-private",
+ },
+ ],
+ "Infrastructure & Operations" => [
+ {
+ link => "form.itrequest",
+ title => "IT Request Form",
+ group => "mozilla-employee-confidential",
+ },
+ {
+ link => "form.mozlist",
+ title => "Mozilla Discussion Forum Requests",
+ group => "mozilla-employee-confidential",
+ },
+ ],
+ "Tech Evangelism" => [
+ {
+ link => "form.mobile.compat",
+ title => "Mobile Web Compatibility Problem",
+ },
+ ],
+ "Air Mozilla" => [
+ {
+ link => "https://air.mozilla.org/requests/",
+ title => "Air Mozilla/Brown Bag Request",
+ group => "mozilla-employee-confidential",
+ },
+ ],
+ "Websites" => [
+ {
+ link => "form.web.bounty",
+ title => "Web Bounty Form",
+ },
+ ],
+ "Firefox OS" => [
+ {
+ link => "form.fxos.feature",
+ title => "Firefox OS Feature Request Form",
+ },
+ {
+ link => "form.fxos.mcts.waiver",
+ title => "Firefox OS MCTS Waiver Form",
+ },
+ {
+ link => "form.fxos.partner",
+ title => "Firefox OS Partner Bug Submission",
+ hide => 1,
+ },
+ {
+ link => "form.fxos.preload.app",
+ title => "Firefox OS Pre-load App",
+ hide => 1,
+ },
+ {
+ link => "form.fxos.betaprogram",
+ title => "Firefox OS Beta Program Bug Submission",
+ hide => 1,
+ },
+ ],
+ "Testing" => [
+ {
+ link => "form.automative",
+ title => "Automation Request Form",
+ },
+ ],
+ "Developer Engagement" => [
+ {
+ link => "form.dev.engagement.event",
+ title => "Developer Events Request Form",
+ },
+ ],
+ "Mozilla Developer Network" => [
+ {
+ link => "form.mdn",
+ title => "Mozilla Developer Network Feedback",
+ },
+ ],
+ "Internet Public Policy" => [
+ {
+ link => "form.ipp",
+ title => "Internet Public Policy Issue",
+ },
+ ],
+ "Marketplace" => [
+ {
+ link => "form.fxos.preload.app",
+ title => "Firefox OS Pre-load App",
+ },
+ ],
+}
+%]
diff --git a/extensions/BMO/template/en/default/bug/create/user-message.html.tmpl b/extensions/BMO/template/en/default/bug/create/user-message.html.tmpl
new file mode 100644
index 000000000..52014ae15
--- /dev/null
+++ b/extensions/BMO/template/en/default/bug/create/user-message.html.tmpl
@@ -0,0 +1,49 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+<p>
+ [% UNLESS cloned_bug_id %]
+ Consider using the
+ <a href="enter_bug.cgi?product=[% product.name FILTER html %]&amp;format=guided"
+ ><img src="extensions/BMO/web/images/guided.png" width="16" height="16" align="absmiddle" border="0">
+ [%+ terms.Bugzilla %] Helper</a> instead of this form.
+ [% END +%]
+ Before reporting a [% terms.bug %], make sure you've read our
+ <a href="http://www.mozilla.org/quality/bug-writing-guidelines.html">
+ [% terms.bug %] writing guidelines</a> and double checked that your [% terms.bug %] hasn't already
+ been reported. Consult our list of <a href="https://bugzilla.mozilla.org/duplicates.cgi">
+ most frequently reported [% terms.bugs %]</a> and <a href="https://bugzilla.mozilla.org/query.cgi">
+ search through descriptions</a> of previously reported [% terms.bugs %].
+</p>
+
+[%
+ PROCESS bug/create/custom_forms.none.tmpl;
+ visible_forms = [];
+ FOREACH form = custom_forms.${product.name};
+ NEXT IF form.hide;
+ NEXT IF form.group && !user.in_group(form.group);
+ visible_forms.push(form);
+ END;
+ RETURN UNLESS visible_forms.size;
+%]
+
+<div id="custom_form_list">
+ <img src="extensions/BMO/web/images/notice.png" width="48" height="48" id="custom_form_list_image">
+ <div id="custom_form_list_text">
+ This product has task-specific [% terms.bug %] forms that should be used if
+ appropriate:
+
+ <ul>
+ [% FOREACH form = visible_forms.sort("title") %]
+ <li><a href="[% form.link FILTER none %]">[% form.title FILTER html %]</a></li>
+ [% END %]
+ </ul>
+ </div>
+</div>
diff --git a/extensions/BMO/template/en/default/email/bugmail.html.tmpl b/extensions/BMO/template/en/default/email/bugmail.html.tmpl
new file mode 100644
index 000000000..7a628ec7f
--- /dev/null
+++ b/extensions/BMO/template/en/default/email/bugmail.html.tmpl
@@ -0,0 +1,204 @@
+[%# 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.
+ #%]
+
+[% PROCESS "global/field-descs.none.tmpl" %]
+[% PROCESS "global/reason-descs.none.tmpl" %]
+
+[% isnew = bug.lastdiffed ? 0 : 1 %]
+<html>
+<head>
+ <base href="[% urlbase FILTER html %]">
+ <style>
+ .comment { font-size: 100% !important; }
+ </style>
+</head>
+<body style="font-family: sans-serif">
+
+ [% IF !to_user.in_group('editbugs') %]
+ <div id="noreply" style="font-size: 90%; color: #666666">
+ Do not reply to this email. You can add comments to this [% terms.bug %] at
+ [%# using the bug_link filter here causes a weird template error %]
+ <a href="[% urlbase FILTER html %]show_bug.cgi?id=[% bug.id FILTER none %]">
+ [% urlbase FILTER html %]show_bug.cgi?id=[% bug.id FILTER none %]</a>
+ </div>
+ <br>
+ [% END %]
+
+ [% IF isnew %]
+ [% PROCESS generate_new %]
+ [% ELSE %]
+ [% PROCESS generate_diffs %]
+ [% END %]
+
+ [% IF new_comments.size %]
+ <div id="comments">
+ [% FOREACH comment = new_comments.reverse %]
+ <div>
+ [% IF comment.count %]
+ <b>
+ [% "Comment # ${comment.count}"
+ FILTER bug_link(bug, { comment_num => comment.count, full_url => 1 }) FILTER none %]
+ on [% "$terms.Bug $bug.id" FILTER bug_link(bug, { full_url => 1 }) FILTER none %]
+ from [% INCLUDE global/user.html.tmpl user = to_user, who = comment.author %]
+ at [% comment.creation_ts FILTER time(undef, to_user.timezone) %]
+ </b>
+ [% END %]
+ <pre class="comment" style="font-size: 120%">[% comment.body_full({ wrap => 1 }) FILTER quoteUrls(bug, comment) %]</pre>
+ </div>
+ [% END %]
+ </div>
+ <br>
+ [% END %]
+
+ [% IF referenced_bugs.size %]
+ <div id="referenced">
+ <hr style="border: 1px dashed #969696">
+ <b>Referenced [% terms.Bugs %]:</b>
+ <ul>
+ [% FOREACH ref = referenced_bugs %]
+ <li>
+ [<a href="[% urlbase FILTER html %]show_bug.cgi?id=[% ref.id FILTER none %]">
+ [% terms.Bug %]&nbsp;[% ref.id FILTER none %]</a>] [% ref.short_desc FILTER html %]
+ </li>
+ [% END %]
+ </ul>
+ </div>
+ <br>
+ [% END %]
+
+ <div id="bug_details" style="font-size: 90%; color: #666666">
+ <hr style="border: 1px dashed #969696">
+ Product/Component: [% bug.product FILTER html %] :: [% bug.component FILTER html %]<br>
+ [% "You are mentoring this " _ terms.bug IF bug.is_mentor(to_user) %]
+ </div>
+
+ [% seen_header = 0 %]
+ [% FOREACH flag = tracking_flags %]
+ [% NEXT IF bug.${flag.name} == "---" %]
+ [% IF !seen_header %]
+ [% seen_header = 1 %]
+ <div id="tracking" style="font-size: 90%; color: #666666">
+ <hr style="border: 1px dashed #969696">
+ <b>Tracking Flags:</b>
+ <ul>
+ [% END %]
+ <li>[% flag.description FILTER html %]:[% bug.${flag.name} FILTER html %]</li>
+ [% END %]
+ [% IF seen_header %]
+ </ul>
+ </div>
+ [% END %]
+
+ <div id="reason" style="font-size: 90%; color: #666666">
+ <hr style="border: 1px dashed #969696">
+ <b>You are receiving this mail because:</b>
+ <ul>
+ [% FOREACH reason = reasons %]
+ [% IF reason_descs.$reason %]
+ <li>[% reason_descs.$reason FILTER html %]</li>
+ [% END %]
+ [% END %]
+ [% FOREACH reason = reasons_watch %]
+ [% IF watch_reason_descs.$reason %]
+ <li>[% watch_reason_descs.$reason FILTER html %]</li>
+ [% END %]
+ [% END %]
+ </ul>
+ </div>
+
+ @@body-headers@@
+</body>
+</html>
+
+[% BLOCK generate_new %]
+ <div class="new">
+ <table border="0" cellspacing="0" cellpadding="3">
+ [% FOREACH change = diffs %]
+ [% PROCESS "email/bugmail-common.txt.tmpl" %]
+ <tr>
+ <td class="c1" style="border-right: 1px solid #969696" nowrap><b>[% field_label FILTER html %]</b></td>
+ <td class="c2">
+ [% IF change.field_name == "bug_id" %]
+ [% new_value FILTER bug_link(bug, full_url => 1) FILTER none %]
+ [% ELSE %]
+ [% new_value FILTER html %]
+ [% END %]
+ </td>
+ </tr>
+ [% END %]
+ </table>
+ </div>
+ <br>
+[% END %]
+
+[% BLOCK generate_diffs %]
+ [% SET in_table = 0 %]
+ [% last_changer = 0 %]
+ [% FOREACH change = diffs %]
+ [% PROCESS "email/bugmail-common.txt.tmpl" %]
+ [% IF changer.id != last_changer %]
+ [% last_changer = changer.id %]
+ [% IF in_table == 1 %]
+ </table>
+ </div>
+ <br>
+ [% SET in_table = 0 %]
+ [% END %]
+
+ <b>
+ [% IF change.blocker %]
+ [% "${terms.Bug} ${bug.id}" FILTER bug_link(bug, full_url => 1) FILTER none %]
+ depends on
+ <a href="[% urlbase FILTER html %]show_bug.cgi?id=[% change.blocker.id FILTER none %]">
+ [% terms.Bug %]&nbsp;[% change.blocker.id FILTER none %]</a>,
+ which changed state.<br>
+ [% ELSE %]
+ [% INCLUDE global/user.html.tmpl user = to_user, who = change.who %] changed
+ [%+ "${terms.Bug} ${bug.id}" FILTER bug_link(bug, full_url => 1) FILTER none %]
+ at [% change.bug_when FILTER time(undef, to_user.timezone) %]</b>:<br>
+ [% END %]
+ </b>
+
+ [% IF in_table == 0 %]
+ <br>
+ <div class="diffs">
+ <table border="0" cellspacing="0" cellpadding="5">
+ [% SET in_table = 1 %]
+ [% END %]
+ <tr class="head">
+ <td class="c1" style="border-bottom: 1px solid #969696; border-right: 1px solid #969696"><b>What</b></td>
+ <td class="c2" style="border-bottom: 1px solid #969696; border-right: 1px solid #969696"><b>Removed</b></td>
+ <td class="c3" style="border-bottom: 1px solid #969696"><b>Added</b></td>
+ </tr>
+ [% END %]
+
+ <tr>
+ <td class="c1" style="border-right: 1px solid #969696" nowrap>[% field_label FILTER html %]</td>
+ <td class="c2" style="border-right: 1px solid #969696">
+ [% IF old_value %]
+ [% old_value FILTER html %]
+ [% ELSE %]
+ &nbsp;
+ [% END %]
+ </td>
+ <td>
+ [% IF new_value %]
+ [% new_value FILTER html %]
+ [% ELSE %]
+ &nbsp;
+ [% END %]
+ </td>
+ </tr>
+ [% END %]
+ [% IF in_table %]
+ </table>
+ </div>
+ <br>
+ [% END %]
+[% END %]
+
diff --git a/extensions/BMO/template/en/default/email/bugmail.txt.tmpl b/extensions/BMO/template/en/default/email/bugmail.txt.tmpl
new file mode 100644
index 000000000..9cb020b02
--- /dev/null
+++ b/extensions/BMO/template/en/default/email/bugmail.txt.tmpl
@@ -0,0 +1,92 @@
+[%# 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.
+ #%]
+
+[% PROCESS "global/field-descs.none.tmpl" %]
+[% PROCESS "global/reason-descs.none.tmpl" %]
+
+[% isnew = bug.lastdiffed ? 0 : 1 %]
+
+[% IF !to_user.in_group('editbugs') %]
+Do not reply to this email. You can add comments to this [% terms.bug %] at
+[% END %]
+[%+ PROCESS generate_diffs -%]
+
+[% FOREACH comment = new_comments %]
+
+[%- IF comment.count %]
+--- Comment #[% comment.count %] from [% comment.author.identity %] [%+ comment.creation_ts FILTER time(undef, to_user.timezone) %] ---
+[% END %]
+[%+ comment.body_full({ is_bugmail => 1, wrap => 1 }) %]
+[% END %]
+[% IF referenced_bugs.size %]
+
+Referenced [% terms.Bugs %]:
+
+[% FOREACH ref = referenced_bugs %]
+[%+ urlbase %]show_bug.cgi?id=[% ref.id %]
+[%+ "[" _ terms.Bug _ " " _ ref.id _ "] " _ ref.short_desc FILTER wrap_comment(76) %]
+[% END %]
+[% END %]
+
+-- [%# Protect the trailing space of the signature marker %]
+Configure [% terms.bug %]mail: [% urlbase %]userprefs.cgi?tab=email
+
+-------------------------------
+Product/Component: [%+ bug.product +%] :: [%+ bug.component %]
+[%+ "You are mentoring this " _ terms.bug IF bug.is_mentor(to_user) %]
+
+[% seen_header = 0 %]
+[% FOREACH flag = tracking_flags %]
+ [% NEXT IF bug.${flag.name} == "---" %]
+ [% IF !seen_header %]
+ [% seen_header = 1 %]
+------- Tracking Flags: -------
+ [% END %]
+[%+ flag.description %]:[% bug.${flag.name} %]
+[% END %]
+
+------- You are receiving this mail because: -------
+[% SET reason_lines = [] %]
+[% FOREACH reason = reasons %]
+ [% reason_lines.push(reason_descs.$reason) IF reason_descs.$reason %]
+[% END %]
+[% FOREACH reason = reasons_watch %]
+ [% reason_lines.push(watch_reason_descs.$reason)
+ IF watch_reason_descs.$reason %]
+[% END %]
+[%+ reason_lines.join("\n") %]
+
+@@body-headers@@
+
+[% BLOCK generate_diffs %]
+ [% urlbase %]show_bug.cgi?id=[% bug.id %]
+
+[%+ last_changer = 0 %]
+ [% FOREACH change = diffs %]
+ [% IF !isnew && changer.id != last_changer %]
+ [% last_changer = changer.id %]
+ [% IF change.blocker %]
+ [% terms.Bug %] [%+ bug.id %] depends on [% terms.bug %] [%+ change.blocker.id %], which changed state.
+
+[%+ terms.Bug %] [%+ change.blocker.id %] Summary: [% change.blocker.short_desc %]
+[%+ urlbase %]show_bug.cgi?id=[% change.blocker.id %]
+ [% ELSE %]
+ [%~ changer.identity %] changed:
+ [% END %]
+
+ What |Removed |Added
+----------------------------------------------------------------------------
+[%+ END %][%# End of IF. This indentation is intentional! ~%]
+ [% PROCESS "email/bugmail-common.txt.tmpl"%]
+ [%~ IF isnew %]
+ [% format_columns(2, field_label _ ":", new_value) -%]
+ [% ELSE %]
+ [% format_columns(3, field_label, old_value, new_value) -%]
+ [% END %]
+ [% END -%]
+[% END %]
diff --git a/extensions/BMO/template/en/default/global/choose-product.html.tmpl b/extensions/BMO/template/en/default/global/choose-product.html.tmpl
new file mode 100644
index 000000000..eb7581d4e
--- /dev/null
+++ b/extensions/BMO/template/en/default/global/choose-product.html.tmpl
@@ -0,0 +1,228 @@
+[%# 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 <gerv@gerv.net>
+ #%]
+
+[%# INTERFACE:
+ # classifications: array of hashes, with an 'object' key representing a
+ # classification object and 'products' the list of
+ # product objects the user can enter bugs into.
+ # target: the script that displays this template.
+ # cloned_bug_id: ID of the bug being cloned.
+ # format: the desired format to display the target.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% style_urls = [ "extensions/BMO/web/styles/choose_product.css" ] %]
+
+[% IF target == "enter_bug.cgi" %]
+ [% title = "Enter $terms.Bug" %]
+ [% h2 = "Which product is affected by the problem you would like to report?" %]
+[% ELSIF target == "describecomponents.cgi" %]
+ [% title = "Browse" %]
+ [% h2 = "Which product would you like to have described?" %]
+[% END %]
+
+[% javascript_urls = [ "js/yui3/yui/yui-min.js",
+ "extensions/ProdCompSearch/web/js/prod_comp_search.js" ]
+%]
+[% onload = "document.getElementById('prod_comp_search').focus();" %]
+[% style_urls.push("extensions/ProdCompSearch/web/styles/prod_comp_search.css") %]
+
+[% DEFAULT title = "Choose a Product" %]
+[% PROCESS global/header.html.tmpl %]
+
+<div id="choose_product">
+
+<hr>
+<p>
+ Looking for technical support or help getting your site to work with Mozilla?
+ <a href="http://www.mozilla.org/support/">Visit the mozilla.org support page</a>
+ before filing [% terms.bugs %].
+</p>
+<hr>
+
+<h2>[% h2 FILTER html %]</h2>
+
+<div id="prod_comp_search_main">
+ [% PROCESS prodcompsearch/form.html.tmpl
+ input_label = "Find product:"
+ format = format
+ cloned_bug_id = cloned_bug_id
+ script_name = target %]
+</div>
+
+<h2>or choose from the following selections</h2>
+
+[% USE Bugzilla %]
+[% cgi = Bugzilla.cgi %]
+[% SET classification = cgi.param('classification') %]
+[% IF NOT ((cgi.param("full")) OR (user.settings.product_chooser.value == 'full_product_chooser')) %]
+
+<table align="center" border="0" width="600" cellpadding="5" cellspacing="0">
+[% INCLUDE easyproduct
+ name="Core"
+ icon="component.png"
+%]
+[% INCLUDE easyproduct
+ name="Firefox"
+ icon="firefox.png"
+%]
+[% INCLUDE easyproduct
+ name="Firefox OS"
+ icon="firefox_os.png"
+%]
+[% INCLUDE easyproduct
+ name="Firefox for Android"
+ icon="firefox_android.png"
+%]
+[% INCLUDE easyproduct
+ name="Marketplace"
+ icon="marketplace.png"
+%]
+[% INCLUDE easyproduct
+ name="Webmaker"
+ icon="webmaker.png"
+%]
+[% INCLUDE easyproduct
+ name="Toolkit"
+ icon="component.png"
+%]
+[% INCLUDE easyproduct
+ name="Thunderbird"
+ icon="thunderbird.png"
+%]
+[% INCLUDE easyproduct
+ name="SeaMonkey"
+ icon="seamonkey.png"
+%]
+[% INCLUDE easyproduct
+ name="Mozilla Localizations"
+ icon="localization.png"
+%]
+[% INCLUDE easyproduct
+ name="Mozilla Services"
+ icon="sync.png"
+%]
+<tr>
+ <td><a href="[% target FILTER uri %]?full=1
+ [%- IF cloned_bug_id %]&amp;cloned_bug_id=[% cloned_bug_id FILTER uri %][% END -%]
+ [%- IF classification %]&amp;classification=[% classification FILTER uri %][% END -%]
+ [%- IF format %]&amp;format=[% format FILTER uri %][% END %]">
+ <img src="extensions/BMO/web/producticons/other.png" height="64" width="64" border="0"></a></td>
+ <td><h2 align="left" style="margin-bottom: 0px;"><a href="[% target FILTER uri %]?full=1
+ [%- IF cloned_bug_id %]&amp;cloned_bug_id=[% cloned_bug_id FILTER uri %][% END -%]
+ [%- IF classification %]&amp;classification=[% classification FILTER uri %][% END -%]
+ [%- IF format %]&amp;format=[% format FILTER uri %][% END %]">
+ Other Products</a></h2>
+ <p style="margin-top: 0px;">Other Mozilla products which aren't listed here</p>
+ </td>
+</tr>
+</table>
+[% ELSE %]
+
+<table>
+
+[% FOREACH c = classifications %]
+ [% IF c.object %]
+ <tr>
+ <td align="right"><h2>[% c.object.name FILTER html %]</h2></td>
+ <td><strong>[%+ c.object.description FILTER html_light %]</strong></td>
+ </tr>
+ [% END %]
+
+ [% FOREACH p = c.products %]
+ [% class = "" %]
+ [% has_entry_groups = 0 %]
+ [% FOREACH gid = p.group_controls.keys %]
+ [% IF p.group_controls.$gid.entry %]
+ [% has_entry_groups = 1 %]
+ [% class = class _ " group_$gid" %]
+ [% END %]
+ [% END %]
+ <tr class="[% "group_secure" IF has_entry_groups +%] [% class FILTER html %]"
+ [%- IF has_entry_groups %] title="This product requires one or more
+ group memberships in order to enter [% terms.bugs %] in it. You have them, but be
+ aware not everyone else does."[% END %]>
+ <th align="right" valign="top">
+ [% IF p.name == "Mozilla PR" AND target == "enter_bug.cgi" AND NOT format AND NOT cgi.param("debug") %]
+ <a href="[% target FILTER uri %]?product=[% p.name FILTER uri -%]
+ [%- IF cloned_bug_id %]&amp;cloned_bug_id=[% cloned_bug_id FILTER uri %][% END %]&amp;format=mozpr">
+ [% p.name FILTER html FILTER no_break %]</a>:&nbsp;
+ [% ELSE %]
+ <a href="[% target FILTER uri %]?product=[% p.name FILTER uri -%]
+ [%- IF cloned_bug_id %]&amp;cloned_bug_id=[% cloned_bug_id FILTER uri %][% END -%]
+ [%- IF format %]&amp;format=[% format FILTER uri %][% END %]">
+ [% p.name FILTER html FILTER no_break %]</a>:&nbsp;
+ [% END %]
+ </th>
+ <td valign="top">[% p.description FILTER html_light %]</td>
+ </tr>
+ [% END %]
+[% END %]
+
+</table>
+
+<br>
+[% IF target == "enter_bug.cgi" AND user.settings.product_chooser.value != 'full_product_chooser' %]
+<p>You can choose to get this screen by default when you click "New [% terms.Bug %]"
+by changing your <a href="userprefs.cgi?tab=settings">preferences</a>.</p>
+[% END %]
+[% END %]
+<br>
+
+</div>
+
+<div id="guided">
+ <a id="guided_img" href="enter_bug.cgi?format=guided"><img
+ src="extensions/BMO/web/images/guided.png" width="16" height="16" border="0" align="absmiddle"></a>
+ <a id="guided_link" href="enter_bug.cgi?format=guided"
+ >Switch to the [% terms.Bugzilla %] Helper</a>
+ | <a href="page.cgi?id=custom_forms.html">Custom [% terms.bug %] entry forms</a>
+</div>
+
+[% PROCESS global/footer.html.tmpl %]
+
+[%###########################################################################%]
+[%# Block for "easy" product sections #%]
+[%###########################################################################%]
+
+[% BLOCK easyproduct %]
+ [% FOREACH c = classifications %]
+ [% FOREACH p = c.products %]
+ [% IF p.name == name %]
+ <tr>
+ <td><a href="[% target FILTER uri %]?product=[% p.name FILTER uri %]
+ [%- IF cloned_bug_id %]&amp;cloned_bug_id=[% cloned_bug_id FILTER uri %][% END -%]
+ [%- IF format %]&amp;format=[% format FILTER uri %][% END %]">
+ <img src="extensions/BMO/web/producticons/[% icon FILTER uri %]" height="64" width="64" border="0"></a></td>
+ <td><h2 align="left" style="margin-bottom: 0px"><a href="[% target FILTER uri %]?product=[% p.name FILTER uri %]
+ [%- IF cloned_bug_id %]&amp;cloned_bug_id=[% cloned_bug_id FILTER uri %][% END -%]
+ [%- IF format %]&amp;format=[% format FILTER uri %][% END %]">
+ [% caption || name FILTER html FILTER no_break %]</a>:</h2>
+ [% IF p.description %]
+ <p style="margin-top: 0px;">[% p.description FILTER html_light %]</p>
+ [% END %]
+ </td>
+ </tr>
+ [% LAST %]
+ [% END %]
+ [% END %]
+ [% END %]
+[% END %]
diff --git a/extensions/BMO/template/en/default/global/prod-comp-search.html.tmpl b/extensions/BMO/template/en/default/global/prod-comp-search.html.tmpl
new file mode 100644
index 000000000..2f1d67bec
--- /dev/null
+++ b/extensions/BMO/template/en/default/global/prod-comp-search.html.tmpl
@@ -0,0 +1,43 @@
+[%# 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.
+ #%]
+
+<div id="prod_comp_search_main">
+ <div id="prod_comp_search_autocomplete">
+ <div id="prod_comp_search_label">
+ Type to find product and component by name or description:
+ <img id="prod_comp_throbber" src="extensions/BMO/web/images/throbber.gif"
+ class="hidden" width="16" height="11">
+ </div>
+ <input id="prod_comp_search" type="text" size="60">
+ <div id="prod_comp_search_autocomplete_container"></div>
+ </div>
+</div>
+<script type="text/javascript">
+ if(typeof(YAHOO.bugzilla.prodCompSearch) !== 'undefined'
+ && YAHOO.bugzilla.prodCompSearch != null)
+ {
+ YAHOO.bugzilla.prodCompSearch.init(
+ "prod_comp_search",
+ "prod_comp_search_autocomplete_container",
+ "[% format FILTER js %]",
+ "[% cloned_bug_id FILTER js %]");
+ [% IF target == "describecomponents.cgi" %]
+ YAHOO.bugzilla.prodCompSearch.autoComplete.itemSelectEvent.subscribe(function (e, args) {
+ var oData = args[2];
+ var url = "describecomponents.cgi?product=" + encodeURIComponent(oData[0]) +
+ "&component=" + encodeURIComponent(oData[1]) +
+ "#" + encodeURIComponent(oData[1]);
+ var format = YAHOO.bugzilla.prodCompSearch.format;
+ if (format) {
+ url += "&format=" + encodeURIComponent(format);
+ }
+ window.location.href = url;
+ });
+ [% END %]
+ }
+</script>
diff --git a/extensions/BMO/template/en/default/global/redirect.html.tmpl b/extensions/BMO/template/en/default/global/redirect.html.tmpl
new file mode 100644
index 000000000..67561d8fa
--- /dev/null
+++ b/extensions/BMO/template/en/default/global/redirect.html.tmpl
@@ -0,0 +1,25 @@
+[%# 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.
+ #%]
+
+<!doctype html>
+<html>
+<head>
+ <title>Moved</title>
+ <meta http-equiv="refresh" content="0;URL=[% url FILTER none %]">
+ <style>
+ body {
+ font-family: sans-serif;
+ font-size: small;
+ background: url('extensions/BMO/web/images/background.png') repeat-x;
+ }
+ </style>
+</head>
+<body>
+ Redirecting to <a href="[% url FILTER none %]">[% url FILTER html %]</a>
+</body>
+</html>
diff --git a/extensions/BMO/template/en/default/hook/admin/params/editparams-current_panel.html.tmpl b/extensions/BMO/template/en/default/hook/admin/params/editparams-current_panel.html.tmpl
new file mode 100644
index 000000000..39f063464
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/admin/params/editparams-current_panel.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 panel.name == "groupsecurity" %]
+ [% panel.param_descs.delete_comments_group =
+ 'The name of the group of users who can delete comments by using the "deleted" comment tag.'
+ %]
+[% END -%]
diff --git a/extensions/BMO/template/en/default/hook/attachment/createformcontents-mimetypes.html.tmpl b/extensions/BMO/template/en/default/hook/attachment/createformcontents-mimetypes.html.tmpl
new file mode 100644
index 000000000..3dc727b87
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/attachment/createformcontents-mimetypes.html.tmpl
@@ -0,0 +1,2 @@
+[% mimetypes.push({type => "image/svg+xml", desc => "SVG image"}) %]
+[% mimetypes.push({type => "application/vnd.mozilla.xul+xml", desc => "XUL"}) %] \ No newline at end of file
diff --git a/extensions/BMO/template/en/default/hook/attachment/createformcontents-patch_notes.html.tmpl b/extensions/BMO/template/en/default/hook/attachment/createformcontents-patch_notes.html.tmpl
new file mode 100644
index 000000000..ea80fdc5e
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/attachment/createformcontents-patch_notes.html.tmpl
@@ -0,0 +1 @@
+<em>You can <a href="http://developer.mozilla.org/en/docs/Getting_your_patch_in_the_tree">read about the patch submission and approval process</a>.</em><br>
diff --git a/extensions/BMO/template/en/default/hook/bug/comments-a_comment-end.html.tmpl b/extensions/BMO/template/en/default/hook/bug/comments-a_comment-end.html.tmpl
new file mode 100644
index 000000000..caf7acca7
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/bug/comments-a_comment-end.html.tmpl
@@ -0,0 +1,19 @@
+[%# 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 user.id && comment.author.login_name == 'tbplbot@gmail.com' %]
+ [% has_tbpl_comment = 1 %]
+ <script>
+ var id = [% count FILTER none %];
+ tbpl_comment_ids.push(id);
+ collapse_comment(
+ document.getElementById('comment_link_' + id),
+ document.getElementById('comment_text_' + id)
+ );
+ </script>
+[% END %]
diff --git a/extensions/BMO/template/en/default/hook/bug/comments-aftercomments.html.tmpl b/extensions/BMO/template/en/default/hook/bug/comments-aftercomments.html.tmpl
new file mode 100644
index 000000000..65bf77967
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/bug/comments-aftercomments.html.tmpl
@@ -0,0 +1,69 @@
+[%# 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 has_tbpl_comment %]
+ [% expand_caption = 'Expand TinderboxPushlog Comments' %]
+ [% collapse_caption = 'Collapse TinderboxPushlog Comments' %]
+ [% show_caption = 'Show TinderboxPushlog Comments' %]
+ [% hide_caption = 'Hide TinderboxPushlog Comments' %]
+ <script>
+ YAHOO.util.Event.onDOMReady(function () {
+ var ul = document.getElementsByClassName('bz_collapse_expand_comments');
+ if (ul.length == 0)
+ return;
+
+ var li = document.createElement('li');
+ var a = document.createElement('a');
+ Dom.setAttribute(a, 'href', 'javascript:void(0)');
+ Dom.setAttribute(a, 'id', 'tbpl_toggle_collapse');
+ a.innerHTML = '[% expand_caption FILTER js %]';
+ YAHOO.util.Event.on(a, 'click', function() {
+ var a = document.getElementById('tbpl_toggle_collapse');
+ var do_expand = a.innerHTML == '[% expand_caption FILTER js %]';
+ for (var i = 0, n = tbpl_comment_ids.length; i < n; i++) {
+ var id = tbpl_comment_ids[i];
+ var link = document.getElementById('comment_link_' + id);
+ var text = document.getElementById('comment_text_' + id);
+ if (do_expand) {
+ expand_comment(link, text);
+ } else {
+ collapse_comment(link, text);
+ }
+ }
+ a.innerHTML = do_expand
+ ? '[% collapse_caption FILTER js %]'
+ : '[% expand_caption FILTER js %]';
+ });
+ li.appendChild(a);
+ ul[0].appendChild(li);
+
+ li = document.createElement('li');
+ a = document.createElement('a');
+ Dom.setAttribute(a, 'href', 'javascript:void(0)');
+ Dom.setAttribute(a, 'id', 'tbpl_toggle_visible');
+ a.innerHTML = '[% hide_caption FILTER js %]';
+ YAHOO.util.Event.on(a, 'click', function() {
+ var a = document.getElementById('tbpl_toggle_visible');
+ var do_show = a.innerHTML == '[% show_caption FILTER js %]';
+ for (var i = 0, n = tbpl_comment_ids.length; i < n; i++) {
+ var id = tbpl_comment_ids[i];
+ if (do_show) {
+ Dom.removeClass('c' + id, 'bz_default_hidden');
+ } else {
+ Dom.addClass('c' + id, 'bz_default_hidden');
+ }
+ }
+ a.innerHTML = do_show
+ ? '[% hide_caption FILTER js %]'
+ : '[% show_caption FILTER js %]';
+ });
+ li.appendChild(a);
+ ul[0].appendChild(li);
+ });
+ </script>
+[% END %]
diff --git a/extensions/BMO/template/en/default/hook/bug/comments-comment_banner.html.tmpl b/extensions/BMO/template/en/default/hook/bug/comments-comment_banner.html.tmpl
new file mode 100644
index 000000000..2ae367456
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/bug/comments-comment_banner.html.tmpl
@@ -0,0 +1,13 @@
+[%# *** Disclaimer for Legal bugs *** %]
+[% IF bug.product == "Legal" %]
+ <div id="legal_disclaimer">
+ The material and information contained herein is Confidential and
+ subject to Attorney-Client Privilege and Work Product Doctrine.
+ </div>
+[% END %]
+
+[%# Needed for collapsing TinderboxPushlog comments %]
+[% has_tbpl_comment = 0 %]
+<script>
+ var tbpl_comment_ids = new Array();
+</script>
diff --git a/extensions/BMO/template/en/default/hook/bug/create/create-after_custom_fields.html.tmpl b/extensions/BMO/template/en/default/hook/bug/create/create-after_custom_fields.html.tmpl
new file mode 100644
index 000000000..47d86bd58
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/bug/create/create-after_custom_fields.html.tmpl
@@ -0,0 +1,30 @@
+[%# 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.
+ #%]
+
+[%# crash-signature handling %]
+[% IF show_crash_signature %]
+ <tbody class="expert_fields">
+ <tr>
+ <th id="field_label_cf_crash_signature" class="field_label">
+ <label for="cf_crash_signature"> Crash Signature: </label>
+ </th>
+ <td colspan="3">
+ <span id="cf_crash_signature_container">
+ <span id="cf_crash_signature_nonedit_display"><i>None</i></span>
+ (<a id="cf_crash_signature_action" href="#">edit</a>)
+ </span>
+ <span id="cf_crash_signature_input">
+ <textarea id="cf_crash_signature" name="cf_crash_signature" rows="4" cols="60"
+ >[% cf_crash_signature FILTER html %]</textarea>
+ </span>
+ </td>
+ </tr>
+ </tbody>
+[% END %]
+
+
diff --git a/extensions/BMO/template/en/default/hook/bug/create/create-custom_field.html.tmpl b/extensions/BMO/template/en/default/hook/bug/create/create-custom_field.html.tmpl
new file mode 100644
index 000000000..afbb2947c
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/bug/create/create-custom_field.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.
+ #%]
+
+[%# crash-signature gets custom handling %]
+[% IF field.name == 'cf_crash_signature' %]
+ [% field.hidden = 1 %]
+ [% show_crash_signature = 1 %]
+[% END %]
diff --git a/extensions/BMO/template/en/default/hook/bug/create/create-end.html.tmpl b/extensions/BMO/template/en/default/hook/bug/create/create-end.html.tmpl
new file mode 100644
index 000000000..a152527ba
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/bug/create/create-end.html.tmpl
@@ -0,0 +1,33 @@
+[%# 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.
+ #%]
+
+[% RETURN UNLESS product.name == 'Bugzilla' &&
+ (user.in_group('mozilla-corporation') || user.in_group('mozilla-foundation')) %]
+
+<div id="bug_create_warning">
+ <div id="bug_create_warning_image">
+ <img src="extensions/BMO/web/images/sign_warning.png" width="32" height="32">
+ </div>
+ <div id="bug_create_warning_text">
+ <b>Mozilla employees</b><br>
+ This is <i>not</i> the place to request configuration, permission, or
+ account changes to this installation of [% terms.Bugzilla %] (bugzilla.mozilla.org).<br>
+ This includes, but is not limited to:
+ <ul>
+ <li>New or updates to products and components</li>
+ <li>Changes to the values of existing fields (versions, milestones, etc)</li>
+ </ul>
+ Instead, please file such changes under
+ <a href="enter_bug.cgi?product=bugzilla.mozilla.org;component=Administration">
+ <b>
+ the Administration component in the bugzilla.mozilla.org
+ </b>
+ </a>
+ product.
+ </div>
+</div>
diff --git a/extensions/BMO/template/en/default/hook/bug/create/create-form.html.tmpl b/extensions/BMO/template/en/default/hook/bug/create/create-form.html.tmpl
new file mode 100644
index 000000000..562ebfbdd
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/bug/create/create-form.html.tmpl
@@ -0,0 +1,47 @@
+ <tr>
+ <th>Security:</th>
+ <td colspan="3">
+ [% IF user.in_group(product.default_security_group) %]
+ [% PROCESS group_checkbox
+ name = product.default_security_group
+ desc = "Restrict access to this " _ terms.bug _ " to members of " _
+ "the \"" _ product.default_security_group_obj.description _ "\" group."
+ %]
+ [% ELSE %]
+ [% PROCESS group_checkbox
+ name = product.default_security_group
+ desc = "Many users could be harmed by this security problem: " _
+ "it should be kept hidden from the public until it is resolved."
+ %]
+ [% END %]
+ [% IF user.in_group('partner-confidential-visible') %]
+ [% PROCESS group_checkbox
+ name = 'partner-confidential'
+ desc = "Restrict the visibility of this " _ terms.bug _ " to " _
+ "the assignee, QA contact, and CC list only."
+ %]
+ [% END %]
+ [% IF user.in_group('mozilla-employee-confidential-visible')
+ && !user.in_group('mozilla-employee-confidential') %]
+ [% PROCESS group_checkbox
+ name = 'mozilla-employee-confidential'
+ desc = "Restrict the visibility of this " _ terms.bug _ " to " _
+ "Mozilla Employees and Contractors only."
+ %]
+ [% END %]
+ <br>
+ </td>
+ </tr>
+
+[% BLOCK group_checkbox %]
+ <input type="checkbox" name="groups"
+ value="[% name FILTER none %]" id="group_[% name FILTER html %]"
+ [% FOREACH group = product.groups_available %]
+ [% IF group.name == name %]
+ [% ' checked="checked"' IF default.groups.contains(group.name) OR group.is_default %]
+ [% LAST %]
+ [% END %]
+ [% END %]
+ >
+ <label for="group_[% name FILTER html %]">[% desc FILTER html %]</label><br>
+[% END %]
diff --git a/extensions/BMO/template/en/default/hook/bug/edit-after_importance.html.tmpl b/extensions/BMO/template/en/default/hook/bug/edit-after_importance.html.tmpl
new file mode 100644
index 000000000..d7c0d58a8
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/bug/edit-after_importance.html.tmpl
@@ -0,0 +1,76 @@
+[%# 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.
+ #%]
+
+[%# Display product and component descriptions after their respective fields %]
+<script type="text/javascript">
+ var Event = YAHOO.util.Event;
+ var Dom = YAHOO.util.Dom;
+ Event.onDOMReady(function() {
+ // Display product description if user requests it
+ var prod_desc = '[% bug.product_obj.description FILTER html_light FILTER js %]';
+ if (prod_desc) {
+ var field_container = Dom.get('field_container_product');
+ var toggle_container = document.createElement('span');
+ Dom.setAttribute(toggle_container, 'id', 'toggle_prod_desc');
+ toggle_container.appendChild(document.createTextNode(' ('));
+ var toggle_link = document.createElement('a');
+ Dom.setAttribute(toggle_link, 'id', 'toggle_prod_desc_link');
+ Dom.setAttribute(toggle_link, 'href', 'javascript:void(0);')
+ toggle_link.appendChild(document.createTextNode('show info'));
+ toggle_container.appendChild(toggle_link);
+ toggle_container.appendChild(document.createTextNode(')'));
+ field_container.appendChild(toggle_container);
+ var desc_container = document.createElement('div');
+ Dom.setAttribute(desc_container, 'id', 'prod_desc_container');
+ Dom.addClass(desc_container, 'bz_default_hidden');
+ desc_container.innerHTML = prod_desc;
+ field_container.appendChild(desc_container);
+ Event.addListener(toggle_link, 'click', function () {
+ if (Dom.hasClass('prod_desc_container', 'bz_default_hidden')) {
+ Dom.get('toggle_prod_desc_link').innerHTML = 'hide info';
+ Dom.removeClass('prod_desc_container', 'bz_default_hidden');
+ }
+ else {
+ Dom.get('toggle_prod_desc_link').innerHTML = 'show info';
+ Dom.addClass('prod_desc_container', 'bz_default_hidden');
+ }
+ });
+ }
+
+ // Display component description if user requests it
+ var comp_desc = '[% bug.component_obj.description FILTER html_light FILTER js %]';
+ if (comp_desc) {
+ var field_container = Dom.get('field_container_component');
+ var toggle_container = document.createElement('span');
+ Dom.setAttribute(toggle_container, 'id', 'toggle_comp_desc');
+ toggle_container.appendChild(document.createTextNode(' ('));
+ var toggle_link = document.createElement('a');
+ Dom.setAttribute(toggle_link, 'id', 'toggle_comp_desc_link');
+ Dom.setAttribute(toggle_link, 'href', 'javascript:void(0);')
+ toggle_link.appendChild(document.createTextNode('show info'));
+ toggle_container.appendChild(toggle_link);
+ toggle_container.appendChild(document.createTextNode(')'));
+ field_container.appendChild(toggle_container);
+ var desc_container = document.createElement('div');
+ Dom.setAttribute(desc_container, 'id', 'comp_desc_container');
+ Dom.addClass(desc_container, 'bz_default_hidden');
+ desc_container.innerHTML = comp_desc;
+ field_container.appendChild(desc_container);
+ Event.addListener(toggle_link, 'click', function () {
+ if (Dom.hasClass('comp_desc_container', 'bz_default_hidden')) {
+ Dom.get('toggle_comp_desc_link').innerHTML = 'hide info';
+ Dom.removeClass('comp_desc_container', 'bz_default_hidden');
+ }
+ else {
+ Dom.get('toggle_comp_desc_link').innerHTML = 'show info';
+ Dom.addClass('comp_desc_container', 'bz_default_hidden');
+ }
+ });
+ }
+ });
+</script>
diff --git a/extensions/BMO/template/en/default/hook/bug/edit-before_restrict_visibility.html.tmpl b/extensions/BMO/template/en/default/hook/bug/edit-before_restrict_visibility.html.tmpl
new file mode 100644
index 000000000..880ab58f7
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/bug/edit-before_restrict_visibility.html.tmpl
@@ -0,0 +1,25 @@
+[%# 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.
+ #%]
+
+[% RETURN IF
+ bug.in_group(bug.product_obj.default_security_group_obj)
+ || user.in_group(bug.product_obj.default_security_group)
+ || (user.id != bug.reporter.id && !user.in_group('editbugs'))
+ %]
+
+<div class="bz_group_visibility_section">
+ <input type="checkbox" name="groups"
+ value="[% bug.product_obj.default_security_group FILTER none %]"
+ id="group_[% bug.product_obj.default_security_group_obj.id FILTER html %]"
+ onchange="if (this.checked) document.getElementById('addselfcc').checked = true"
+ >
+ <label for="group_[% bug.product_obj.default_security_group_obj.id FILTER html %]"
+ title="This [% terms.bug %] is security sensitive and should be hidden from the public until it is resolved">
+ Restrict access to this [% terms.bug %]
+ </label>
+</div><br>
diff --git a/extensions/BMO/template/en/default/hook/bug/field-help-end.none.tmpl b/extensions/BMO/template/en/default/hook/bug/field-help-end.none.tmpl
new file mode 100644
index 000000000..dda75a9c6
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/bug/field-help-end.none.tmpl
@@ -0,0 +1,96 @@
+[%# 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 BMO 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):
+ # Dave Lawrence <dkl@mozilla.com>
+ #%]
+
+[% USE Bugzilla %]
+[% IF Bugzilla.request_cache.bmo_fields_page %]
+ [%
+ vars.help_html.priority =
+ "This field describes the importance and order in which $terms.abug
+ should be fixed compared to other ${terms.bugs}. This field is utilized
+ by the programmers/engineers to prioritize their work to be done where
+ P1 is considered the highest and P5 is the lowest."
+
+ vars.help_html.bug_severity =
+ "This field describes the impact of ${terms.abug}.
+ <table>
+ <tr>
+ <th>blocker</th>
+ <td>Blocks development and/or testing work</td>
+ </tr>
+ <tr>
+ <th>critical</th>
+ <td>crashes, loss of data, severe memory leak</td>
+ </tr>
+ <tr>
+ <th>major</th>
+ <td>major loss of function</td>
+ </tr>
+ <tr>
+ <th>normal</th>
+ <td>regular issue, some loss of functionality under specific circumstances</td>
+ </tr>
+ <tr>
+ <th>minor</th>
+ <td>minor loss of function, or other problem where easy
+ workaround is present</td>
+ </tr>
+ <tr>
+ <th>trivial</th>
+ <td>cosmetic problem like misspelled words or misaligned
+ text</td>
+ </tr>
+ <tr>
+ <th>enhancement</th>
+ <td>Request for enhancement</td>
+ </table>"
+
+ vars.help_html.rep_platform =
+ "This is the hardware platform against which the $terms.bug was reported.
+ Legal platforms include:
+ <ul>
+ <li>All (happens on all platforms; cross-platform ${terms.bug})</li>
+ <li>x86_64</li>
+ <li>ARM</li>
+ </ul>
+ <b>Note:</b> When searching, selecting the option
+ <em>All</em> does not
+ select $terms.bugs assigned against any platform. It merely selects
+ $terms.bugs that are marked as occurring on all platforms, i.e. are
+ designated <em>All</em>.",
+
+ vars.help_html.op_sys =
+ "This is the operating system against which the $terms.bug was
+ reported. Legal operating systems include:
+ <ul>
+ <li>All (happens on all operating systems; cross-platform ${terms.bug})</li>
+ <li>Windows 7</li>
+ <li>Mac OS X</li>
+ <li>Linux</li>
+ </ul>
+ Sometimes the operating system implies the platform, but not
+ always. For example, Linux can run on x86_64, ARM, and others.",
+
+ vars.help_html.assigned_to =
+ "This is the person in charge of resolving the ${terms.bug}. Every time
+ this field changes, the status changes to
+ <b>NEW</b> to make it
+ easy to see which new $terms.bugs have appeared on a person's list.</p>",
+ %]
+[% END %]
diff --git a/extensions/BMO/template/en/default/hook/bug/process/header-title.html.tmpl b/extensions/BMO/template/en/default/hook/bug/process/header-title.html.tmpl
new file mode 100644
index 000000000..a99b4f9f6
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/bug/process/header-title.html.tmpl
@@ -0,0 +1,9 @@
+[%# 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.
+ #%]
+
+[% title = title.replace('^' _ terms.Bug _ ' ', '') %]
diff --git a/extensions/BMO/template/en/default/hook/bug/show-header-end.html.tmpl b/extensions/BMO/template/en/default/hook/bug/show-header-end.html.tmpl
new file mode 100644
index 000000000..5ab189045
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/bug/show-header-end.html.tmpl
@@ -0,0 +1,18 @@
+[%# 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.
+ #%]
+
+[% style_urls.push('extensions/BMO/web/styles/edit_bug.css') %]
+[% javascript_urls.push('extensions/BMO/web/js/edit_bug.js') %]
+[% title = "$bug.bug_id &ndash; " %]
+[% IF bug.alias != '' %]
+ [% title = title _ "($bug.alias) " %]
+[% END %]
+[% title = title _ filtered_desc %]
+[% javascript = javascript _
+ "document.title = document.title.replace(/^" _ terms.Bug _ " /, '');"
+%]
diff --git a/extensions/BMO/template/en/default/hook/global/field-descs-end.none.tmpl b/extensions/BMO/template/en/default/hook/global/field-descs-end.none.tmpl
new file mode 100644
index 000000000..8c543b35d
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/global/field-descs-end.none.tmpl
@@ -0,0 +1,12 @@
+[%# 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 in_template_var %]
+ [% vars.field_descs.cc_count = "CC Count" %]
+ [% vars.field_descs.dupe_count = "Duplicate Count" %]
+[% END %]
diff --git a/extensions/BMO/template/en/default/hook/global/footer-end.html.tmpl b/extensions/BMO/template/en/default/hook/global/footer-end.html.tmpl
new file mode 100644
index 000000000..f14b34acb
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/global/footer-end.html.tmpl
@@ -0,0 +1,11 @@
+[%# 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.
+ #%]
+
+<div id="privacy-policy">
+ <a href="https://www.mozilla.org/privacy/websites/" target="_blank">Privacy Policy</a>
+</div>
diff --git a/extensions/BMO/template/en/default/hook/global/header-additional_header.html.tmpl b/extensions/BMO/template/en/default/hook/global/header-additional_header.html.tmpl
new file mode 100644
index 000000000..f1896dccc
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/global/header-additional_header.html.tmpl
@@ -0,0 +1,54 @@
+[%#
+ # 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 BMOHeader Bugzilla Extension.
+ #
+ # The Initial Developer of the Original Code is Reed Loden.
+ # Portions created by the Initial Developer are Copyright (C) 2010 the
+ # Initial Developer. All Rights Reserved.
+ #
+ # Contributor(s):
+ # Reed Loden <reed@reedloden.com>
+ #%]
+
+<link rel="shortcut icon" href="extensions/BMO/web/images/favicon.ico">
+[% IF bug %]
+<link id="shorturl" rev="canonical" href="https://bugzil.la/[% bug.bug_id FILTER uri %]">
+[% END %]
+
+[%# *** Bug List Navigation *** %]
+[% IF bug %]
+ [% SET my_search = user.recent_search_for(bug) %]
+ [% IF my_search %]
+ [% SET last_bug_list = my_search.bug_list %]
+ [% SET this_bug_idx = lsearch(last_bug_list, bug.id) %]
+ <link rel="Up" href="buglist.cgi?regetlastlist=
+ [%- my_search.id FILTER uri %]">
+ <link rel="First" href="show_bug.cgi?id=
+ [%- last_bug_list.first FILTER uri %]&amp;list_id=
+ [%- my_search.id FILTER uri %]">
+ <link rel="Last" href="show_bug.cgi?id=
+ [%- last_bug_list.last FILTER uri %]&amp;list_id=
+ [%- my_search.id FILTER uri %]">
+ [% IF this_bug_idx > 0 %]
+ [% prev_bug = this_bug_idx - 1 %]
+ <link rel="Prev" href="show_bug.cgi?id=
+ [%- last_bug_list.$prev_bug FILTER uri %]&amp;list_id=
+ [%- my_search.id FILTER uri %]">
+ [% END %]
+ [% IF this_bug_idx + 1 < last_bug_list.size %]
+ [% next_bug = this_bug_idx + 1 %]
+ <link rel="Next" href="show_bug.cgi?id=
+ [%- last_bug_list.$next_bug FILTER uri %]&amp;list_id=
+ [%- my_search.id FILTER uri %]">
+ [% END %]
+ [% END %]
+[% END %]
diff --git a/extensions/BMO/template/en/default/hook/global/header-start.html.tmpl b/extensions/BMO/template/en/default/hook/global/header-start.html.tmpl
new file mode 100644
index 000000000..2b2642148
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/global/header-start.html.tmpl
@@ -0,0 +1,41 @@
+[% IF !javascript_urls %]
+ [% javascript_urls = [] %]
+[% END %]
+
+[% IF template.name == 'list/list.html.tmpl' %]
+ [% javascript_urls.push('extensions/BMO/web/js/sorttable.js') %]
+[% END %]
+
+[% IF !bodyclasses %]
+ [% bodyclasses = [] %]
+[% END %]
+
+[%# Change the background/border for bugs/attachments in certain bug groups %]
+[% IF template.name == 'attachment/edit.html.tmpl'
+ || template.name == 'attachment/create.html.tmpl'
+ || template.name == 'attachment/diff-header.html.tmpl' %]
+ [% style_urls.push("skins/custom/bug_groups.css") %]
+
+ [% IF template.name == 'attachment/edit.html.tmpl'
+ || template.name == 'attachment/diff-header.html.tmpl' %]
+ [% IF bodyclasses == 'no_javascript' %]
+ [% bodyclasses = ['no_javascript'] %]
+ [% END %]
+ [% FOREACH group = attachment.bug.groups_in %]
+ [% bodyclasses.push("bz_group_$group.name") %]
+ [% END %]
+ [% END %]
+
+ [% IF template.name == 'attachment/create.html.tmpl' %]
+ [% FOREACH group = bug.groups_in %]
+ [% bodyclasses.push("bz_group_$group.name") %]
+ [% END %]
+ [% END %]
+[% END %]
+
+[%# BMO - add user context menu %]
+[% IF user.id %]
+ [% yui.push('container', 'menu') %]
+ [% style_urls.push('js/yui/assets/skins/sam/menu.css') %]
+ [% javascript_urls.push('extensions/BMO/web/js/edituser_menu.js') %]
+[% END %]
diff --git a/extensions/BMO/template/en/default/hook/global/messages-messages.html.tmpl b/extensions/BMO/template/en/default/hook/global/messages-messages.html.tmpl
new file mode 100644
index 000000000..0c90b97b9
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/global/messages-messages.html.tmpl
@@ -0,0 +1,5 @@
+[% IF message_tag == "employee_incident_creation_failed" %]
+ The [% terms.bug %] was created successfully, but the dependent
+ Employee Incident [% terms.bug %] creation failed. The error has
+ been logged and no further action is required at this time.
+[% END %]
diff --git a/extensions/BMO/template/en/default/hook/global/setting-descs-settings.none.tmpl b/extensions/BMO/template/en/default/hook/global/setting-descs-settings.none.tmpl
new file mode 100644
index 000000000..57e20108d
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/global/setting-descs-settings.none.tmpl
@@ -0,0 +1,14 @@
+[%# 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.
+ #%]
+
+[%
+ setting_descs.product_chooser = "Product chooser to use when entering bugs",
+ setting_descs.pretty_product_chooser = "Pretty chooser with common products and icons",
+ setting_descs.full_product_chooser = "Full chooser with all products",
+ setting_descs.headers_in_body = "Include X-Bugzilla- headers in BugMail body",
+%]
diff --git a/extensions/BMO/template/en/default/hook/global/user-error-auth_failure_object.html.tmpl b/extensions/BMO/template/en/default/hook/global/user-error-auth_failure_object.html.tmpl
new file mode 100644
index 000000000..bf46ed895
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/global/user-error-auth_failure_object.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.
+ #%]
+
+[% IF object == 'group_admins' %]
+ the group administrators report
+[% ELSIF object == 'email_queue' %]
+ the email queue status report
+[% ELSIF object == 'product_security' %]
+ the product security report
+[% ELSIF object == 'comments' %]
+ comments
+[% END %]
diff --git a/extensions/BMO/template/en/default/hook/global/user-error-error_message.html.tmpl b/extensions/BMO/template/en/default/hook/global/user-error-error_message.html.tmpl
new file mode 100644
index 000000000..c7fb31009
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/global/user-error-error_message.html.tmpl
@@ -0,0 +1,26 @@
+[%# 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 == 'illegal_change' || error == 'illegal_change_deps' %]
+ <p>
+ If you are attempting to confirm an unconfirmed [% terms.bug %] or edit the
+ fields of a [% terms.bug %], <a href="page.cgi?id=get_permissions.html">find
+ out how to get the necessary permissions</a>.
+ </p>
+[% END %]
+
+[% IF error == 'entry_access_denied' && product == 'Legal' %]
+ <p>
+ Unfortunately, we need to keep [% terms.bugs %] in the Legal product
+ restricted to employees, in order to preserve attorney-client privilege and
+ protect confidentiality. Due to the way [% terms.Bugzilla %] works, this
+ means we can't let you file such [% terms.abug %] yourself. However, you
+ can contact Mozilla Legal through either legal-notices@mozilla.com or
+ trademarks@mozilla.com, as appropriate.
+ </p>
+[% END %]
diff --git a/extensions/BMO/template/en/default/hook/global/user-error-errors.html.tmpl b/extensions/BMO/template/en/default/hook/global/user-error-errors.html.tmpl
new file mode 100644
index 000000000..aaf23fff5
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/global/user-error-errors.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 BMO 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>
+ #%]
+
+[% IF error == "user_activity_missing_username" %]
+ [% title = "Missing Username" %]
+ You must provide at least one email address to report on.
+
+[% ELSIF error == "report_invalid_date" %]
+ [% title = "Invalid Date" %]
+ The date '[% date FILTER html %]' is invalid.
+
+[% ELSIF error == "report_invalid_parameter" %]
+ [% title = "Invalid Parameter" %]
+ The value for parameter [% name FILTER html %] is invalid.
+
+[% ELSIF error == "invalid_object" %]
+ Invalid [% object FILTER html %]: "[% value FILTER html %]"
+
+[% ELSIF error == "report_too_many_bugs" %]
+ [% title = "Too Many Bugs" %]
+ Too many [% terms.bugs %] matched your selection criteria.
+
+[% END %]
diff --git a/extensions/BMO/template/en/default/hook/global/user-error.html.tmpl/auth_failure/permissions.html.tmpl b/extensions/BMO/template/en/default/hook/global/user-error.html.tmpl/auth_failure/permissions.html.tmpl
new file mode 100644
index 000000000..346e02373
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/global/user-error.html.tmpl/auth_failure/permissions.html.tmpl
@@ -0,0 +1,29 @@
+<!-- 1.0@bugzilla.org -->
+[%# 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 <gerv@gerv.net>
+ # Reed Loden <reed@reedloden.com>
+ #%]
+
+[% IF (group == "canconfirm" OR group == "editbugs") AND !reason %]
+ <p>
+ If you are attempting to confirm an unconfirmed [% terms.bug %] or edit the fields of a [% terms.bug %],
+ <a href="http://www.gerv.net/hacking/before-you-mail-gerv.html#bugzilla-permissions">find
+ out how to get the necessary permissions</a>.
+ </p>
+[% END %]
diff --git a/extensions/BMO/template/en/default/hook/global/variables-end.none.tmpl b/extensions/BMO/template/en/default/hook/global/variables-end.none.tmpl
new file mode 100644
index 000000000..89eef6fc4
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/global/variables-end.none.tmpl
@@ -0,0 +1,3 @@
+[%
+ terms.BugzillaTitle = "Bugzilla@Mozilla"
+%]
diff --git a/extensions/BMO/template/en/default/hook/index-additional_links.html.tmpl b/extensions/BMO/template/en/default/hook/index-additional_links.html.tmpl
new file mode 100644
index 000000000..cfc224fcd
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/index-additional_links.html.tmpl
@@ -0,0 +1,18 @@
+[%# 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.
+ #%]
+
+<li>
+|
+<a href="page.cgi?id=etiquette.html">
+ [%- terms.Bugzilla %] Etiquette</a>
+</li>
+<li>
+|
+<a href="https://developer.mozilla.org/en/Bug_writing_guidelines">
+ [%- terms.Bug %] Writing Guidelines</a>
+</li>
diff --git a/extensions/BMO/template/en/default/hook/index-intro.html.tmpl b/extensions/BMO/template/en/default/hook/index-intro.html.tmpl
new file mode 100644
index 000000000..d81d91491
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/index-intro.html.tmpl
@@ -0,0 +1,2 @@
+<a id="get_help" class="bz_common_actions"
+ href="page.cgi?id=get_help.html"><span>Get Help</span></a> \ No newline at end of file
diff --git a/extensions/BMO/template/en/default/hook/list/list-links.html.tmpl b/extensions/BMO/template/en/default/hook/list/list-links.html.tmpl
new file mode 100644
index 000000000..fda2b43a9
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/list/list-links.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.
+ #%]
+
+<a href="rest/bug?include_fields=id,summary,status&amp;
+ [% IF quicksearch ~%]
+ quicksearch=[% quicksearch FILTER uri %]
+ [% ELSE %]
+ [% cgi.canonicalise_query('list_id', 'query_format') FILTER none %]"
+ [% END %]"
+ title="Query as a REST API request">REST</a> |
diff --git a/extensions/BMO/template/en/default/hook/list/table-before_table.html.tmpl b/extensions/BMO/template/en/default/hook/list/table-before_table.html.tmpl
new file mode 100644
index 000000000..35d7cd3f3
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/list/table-before_table.html.tmpl
@@ -0,0 +1,9 @@
+[%# 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.
+ #%]
+[% abbrev.product.maxlength = 20 %]
+[% abbrev.component.maxlength = 20 %]
diff --git a/extensions/BMO/template/en/default/hook/pages/fields-resolution.html.tmpl b/extensions/BMO/template/en/default/hook/pages/fields-resolution.html.tmpl
new file mode 100644
index 000000000..4d12ab345
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/pages/fields-resolution.html.tmpl
@@ -0,0 +1,13 @@
+<dt>
+ [% display_value("resolution", "INCOMPLETE") FILTER html %]
+</dt>
+<dd>
+ The problem is vaguely described with no steps to reproduce,
+ or is a support request. The reporter should be directed to the
+ product's support page for help diagnosing the issue. If there
+ are only a few comments in the [% terms.bug %], it may be reopened only if
+ the original reporter provides more info, or confirms someone
+ else's steps to reproduce. If the [% terms.bug %] is long, when enough info
+ is provided a new [% terms.bug %] should be filed and the original [% terms.bug %]
+ marked as a duplicate of it.
+</dd>
diff --git a/extensions/BMO/template/en/default/hook/reports/menu-end.html.tmpl b/extensions/BMO/template/en/default/hook/reports/menu-end.html.tmpl
new file mode 100644
index 000000000..93f04c4fa
--- /dev/null
+++ b/extensions/BMO/template/en/default/hook/reports/menu-end.html.tmpl
@@ -0,0 +1,59 @@
+[%# 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.
+ #%]
+
+<h2>Other Reports</h2>
+
+<ul>
+ <li>
+ <strong>
+ <a href="[% urlbase FILTER none %]page.cgi?id=user_activity.html">User Changes</a>
+ </strong> - Show changes made by an individual user.
+ </li>
+ <li>
+ <strong>
+ <a href="[% urlbase FILTER none %]page.cgi?id=triage_reports.html">Triage Report</a>
+ </strong> - Report on UNCONFIRMED [% terms.bugs %] to assist triage.
+ </li>
+ <li>
+ <strong>
+ <a href="[% urlbase FILTER none %]page.cgi?id=release_tracking_report.html">Release Tracking Report</a>
+ </strong> - For triaging release-train flag information.
+ </li>
+ [% IF user.in_group('editusers') || user.in_group('infrasec') %]
+ <li>
+ <strong>
+ <a href="[% urlbase FILTER none %]page.cgi?id=group_admins.html">Group Admins</a>
+ </strong> - Lists the administrators of each group.
+ </li>
+ <li>
+ <strong>
+ <a href="[% urlbase FILTER none %]page.cgi?id=group_membership.html">Group Membership Report</a>
+ </strong> - Lists the groups a user is a member of.
+ </li>
+ <li>
+ <strong>
+ <a href="[% urlbase FILTER none %]page.cgi?id=group_members.html">Group Members Report</a>
+ </strong> - Lists the users of groups.
+ </li>
+ [% END %]
+ [% IF user.in_group('admin') || user.in_group('infrasec') %]
+ <li>
+ <strong>
+ <a href="[% urlbase FILTER none %]page.cgi?id=product_security_report.html">Product Security Report</a>
+ </strong> - Show each product's default security group and visibility.
+ </li>
+ [% END %]
+ [% IF user.in_group('admin') || user.in_group('infra') %]
+ <li>
+ <strong>
+ <a href="[% urlbase FILTER none %]page.cgi?id=email_queue.html">Email Queue</a>
+ </strong> - TheSchwartz queue
+ </li>
+ [% END %]
+</ul>
+
diff --git a/extensions/BMO/template/en/default/list/list.microsummary.tmpl b/extensions/BMO/template/en/default/list/list.microsummary.tmpl
new file mode 100644
index 000000000..8925db8dd
--- /dev/null
+++ b/extensions/BMO/template/en/default/list/list.microsummary.tmpl
@@ -0,0 +1,29 @@
+[%# 1.0@bugzilla.org %]
+[%# 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): Ronaldo Maia <rmaia@everythingsolved.com>
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+
+[% IF searchname %]
+ [% searchname FILTER html %] ([% bugs.size %])
+[% ELSE %]
+ [% terms.Bug %] List ([% bugs.size %])
+[% END %]
diff --git a/extensions/BMO/template/en/default/list/server-push.html.tmpl b/extensions/BMO/template/en/default/list/server-push.html.tmpl
new file mode 100644
index 000000000..1c1f3cf36
--- /dev/null
+++ b/extensions/BMO/template/en/default/list/server-push.html.tmpl
@@ -0,0 +1,52 @@
+[%# 1.0@bugzilla.org %]
+[%# 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): Myk Melez <myk@mozilla.org>
+ #%]
+
+[%# INTERFACE:
+ # debug: boolean. True if we want the search displayed while we wait.
+ # query: string. The SQL query which makes the buglist.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+<html>
+ <head>
+ <title>[% terms.Bugzilla %] is pondering your search</title>
+ </head>
+ <body>
+ <div style="margin-top: 15%; text-align: center;">
+ <center><img src="extensions/BMO/web/images/mozchomp.gif" alt=""
+ width="160" height="87"></center>
+ <h1>Please wait while your [% terms.bugs %] are retrieved.</h1>
+ </div>
+
+ [% IF debug %]
+ <p>
+ [% FOREACH debugline = debugdata %]
+ <code>[% debugline FILTER html %]</code><br>
+ [% END %]
+ </p>
+ <p>
+ <code>[% query FILTER html %]</code>
+ </p>
+ [% END %]
+
+ </body>
+</html>
diff --git a/extensions/BMO/template/en/default/pages/bug-writing.html.tmpl b/extensions/BMO/template/en/default/pages/bug-writing.html.tmpl
new file mode 100644
index 000000000..21ed3b040
--- /dev/null
+++ b/extensions/BMO/template/en/default/pages/bug-writing.html.tmpl
@@ -0,0 +1,11 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/redirect.html.tmpl
+ url = "https://developer.mozilla.org/en/Bug_writing_guidelines"
+%]
diff --git a/extensions/BMO/template/en/default/pages/custom_forms.html.tmpl b/extensions/BMO/template/en/default/pages/custom_forms.html.tmpl
new file mode 100644
index 000000000..d484d730c
--- /dev/null
+++ b/extensions/BMO/template/en/default/pages/custom_forms.html.tmpl
@@ -0,0 +1,40 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/header.html.tmpl
+ title = "Custom Bug Entry Forms"
+%]
+
+[%
+ visible_forms = {};
+ PROCESS bug/create/custom_forms.none.tmpl;
+ FOREACH product = custom_forms.keys;
+ product_forms = [];
+ FOREACH form = custom_forms.$product;
+ NEXT IF form.group && !user.in_group(form.group);
+ product_forms.push(form);
+ END;
+ NEXT UNLESS product_forms.size;
+ visible_forms.$product = product_forms;
+ END;
+%]
+
+<h1>Custom [% terms.Bug %] Entry Forms</h1>
+
+[% FOREACH product = visible_forms.keys.sort %]
+ <h3>[% product FILTER html %]</h3>
+ <ul>
+ [% FOREACH form = visible_forms.$product.sort("title") %]
+ <li>
+ <a href="[% form.link FILTER none %]">[% form.title FILTER html %]</a>
+ </li>
+ [% END %]
+ </ul>
+[% END %]
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/pages/email_queue.html.tmpl b/extensions/BMO/template/en/default/pages/email_queue.html.tmpl
new file mode 100644
index 000000000..f0c750129
--- /dev/null
+++ b/extensions/BMO/template/en/default/pages/email_queue.html.tmpl
@@ -0,0 +1,67 @@
+[%# 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.
+ #%]
+
+[% INCLUDE global/header.html.tmpl
+ title = "Job Queue Status"
+ style_urls = [ "extensions/BMO/web/styles/reports.css" ]
+%]
+
+[% IF jobs.size %]
+
+ <p><i>[% jobs.size FILTER none %] email(s) in the queue.</i></p>
+
+ <table id="report" class="hover" cellspacing="0" border="0" width="100%">
+ <tr id="report-header">
+ <th>Insert Time</th>
+ <th>Run Time</th>
+ <th>Age</th>
+ <th>Error Count</th>
+ <th>Last Error</th>
+ <th>Error Message</th>
+ </tr>
+ [% FOREACH job IN jobs %]
+ <tr class="report item [% loop.count % 2 == 1 ? "report_row_odd" : "report_row_even" %]">
+ <td nowrap>[% time2str("%Y-%m-%d %H:%M:%S %Z", job.insert_time) FILTER html %]</td>
+ <td nowrap>[% time2str("%Y-%m-%d %H:%M:%S %Z", job.run_time) FILTER html %]</td>
+ <td nowrap>
+ [% age = now - job.insert_time %]
+ [% IF age < 60 %]
+ [% age FILTER none %]s
+ [% ELSIF age < 60 * 60 %]
+ [% age / 60 FILTER format('%.0f') %]m
+ [% ELSE %]
+ [% age / (60 * 60) FILTER format('%.0f') %]h
+ [% END %]
+ </td>
+ <td nowrap>[% job.error_count FILTER html %]</td>
+ <td nowrap>
+ [% IF job.error_count %]
+ [% time2str("%Y-%m-%d %H:%M:%S %Z", job.error_time) FILTER html %]
+ [% ELSE %]
+ -
+ [% END %]
+ </td>
+ <td>
+ [% job.error_count ? job.error_message : '-' FILTER html %]
+ </td>
+ </tr>
+ [% IF job.subject %]
+ <tr class="report item [% loop.count % 2 == 1 ? "report_row_odd" : "report_row_even" %]">
+ <td colspan="6">&nbsp;&nbsp;&nbsp;[% job.subject FILTER html %]</td>
+ </tr>
+ [% END %]
+ [% END %]
+ </table>
+
+[% ELSE %]
+
+<p><i>The email queue is empty.</i></p>
+
+[% END %]
+
+[% INCLUDE global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/pages/etiquette.html.tmpl b/extensions/BMO/template/en/default/pages/etiquette.html.tmpl
new file mode 100644
index 000000000..78cc0bad7
--- /dev/null
+++ b/extensions/BMO/template/en/default/pages/etiquette.html.tmpl
@@ -0,0 +1,146 @@
+<!-- 1.0@bugzilla.org -->
+[%# 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): Stefan Seifert <nine@detonation.org>
+ # Gervase Markham <gerv@gerv.net>
+ #%]
+
+[% PROCESS global/header.html.tmpl
+ title = "Bugzilla Etiquette"
+ style = "li { margin: 5px } .heading { font-weight: bold }" %]
+
+<p>
+ There's a number of <i lang="fr">faux pas</i> you can commit when using
+ [%+ terms.Bugzilla %]. At the very
+ least, these will make Mozilla contributors upset at you; if committed enough
+ times they will cause those contributors to demand the disabling of your
+ [%+ terms.Bugzilla %] account. So, ignore this advice at your peril.
+</p>
+
+<p>
+ That said, Mozilla developers are generally a friendly bunch, and will be
+ friendly towards you as long as you follow these guidelines.
+</p>
+
+<h3>1. Commenting</h3>
+
+<p>
+ This is the most important section.
+</p>
+
+<ol>
+ <li>
+ <span class="heading">No pointless comments</span>.
+ Unless you have something constructive and helpful to say, do not add a
+ comment to a [% terms.bug %]. In [% terms.bugs %] where there is a heated debate going on, you
+ should be even more
+ inclined not to add a comment. Unless you have something new to contribute,
+ then the [% terms.bug %] owner is aware of all the issues, and will make a judgement
+ as to what to do. If you agree the [% terms.bug %] should be fixed, vote for it.
+ Additional "I see this too" or "It works for me" comments are unnecessary
+ unless they are on a different platform or a significantly different build.
+ Constructive and helpful thoughts unrelated to the topic of the [% terms.bug %]
+ should go in the appropriate
+ <a href="http://www.mozilla.org/about/forums/">newsgroup</a>.
+ </li>
+
+ <li>
+ <span class="heading">No obligation</span>.
+ "Open Source" is not the same as "the developers must do my bidding."
+ Everyone here wants to help, but no one else has any <i>obligation</i> to fix
+ the [% terms.bugs %] you want fixed. Therefore, you should not act as if you
+ expect someone to fix a [% terms.bug %] by a particular date or release.
+ Aggressive or repeated demands will not be received well and will almost
+ certainly diminish the impact and interest in your suggestions.
+ </li>
+
+ <li>
+ <span class="heading">No abusing people</span>.
+ Constant and intense critique is one of the reasons we build great products.
+ It's harder to fall into group-think if there is always a healthy amount of
+ dissent. We want to encourage vibrant debate inside of the Mozilla
+ community, we want you to disagree with us, and we want you to effectively
+ argue your case. However, we require that in the process, you attack
+ <i>things</i>, not <i>people</i>. Examples of things include: interfaces,
+ algorithms, and schedules. Examples of people include: developers,
+ designers and users. <b>Attacking a person may result in you being banned
+ from [% terms.Bugzilla %].</b>
+ </li>
+
+ <li>
+ <span class="heading">No private email</span>.
+ Unless the [% terms.bug %] owner or another respected project contributor has asked you
+ to email them with specific information, please place all information
+ relating to [% terms.bugs %]
+ in the [% terms.bug %] itself. Do not send them by private email; no-one else can read
+ them if you do that, and they'll probably just get ignored. If a file
+ is too big for [% terms.Bugzilla %], add a comment giving the file size and contents
+ and ask what to do.
+ </li>
+</ol>
+
+<h3>2. Changing Fields</h3>
+
+<ol>
+ <li>
+ <span class="heading">No messing with other people's [% terms.bugs %]</span>.
+ Unless you are the [% terms.bug %] assignee, or have some say over the use of their
+ time, never change the Priority or Target Milestone fields. If in doubt,
+ do not change the fields of [% terms.bugs %] you do not own - add a comment
+ instead, suggesting the change.
+ </li>
+
+ <li>
+ <span class="heading">No whining about decisions</span>.
+ If a respected project contributor has marked a [% terms.bug %] as INVALID, then it is
+ invalid. Someone filing another duplicate of it does not change this. Unless
+ you have further important evidence, do not post a comment arguing that an
+ INVALID or WONTFIX [% terms.bug %] should be reopened.
+ </li>
+
+</ol>
+
+<h3>3. Applicability</h3>
+
+<ol>
+ <li>
+ Some of these rules may not apply to you. If they do not, you will know
+ exactly which ones do not, and why they do not apply. If you are not
+ sure, then they definitely all apply to you.
+ </li>
+</ol>
+
+<p>
+ If you see someone not following these rules, the first step is, as an exception
+ to guideline 1.4, to make them aware of this document by <em>private</em> mail.
+ Flaming people publically in [% terms.bugs %] violates guidelines 1.1 and 1.3. In the case of
+ persistent offending you should ping an administrator on Mozilla IRC in channel #bmo and ask them
+ to look into it.
+</p>
+
+<p>
+ This entire document can be summed up in one sentence:
+ do unto others as you would have them do unto you.
+</p>
+
+<p>
+ Other useful documents:
+ <a href="page.cgi?id=bug-writing.html">The [% terms.Bug %] Writing Guidelines</a>.
+</p>
+
+[% INCLUDE global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/pages/get_help.html.tmpl b/extensions/BMO/template/en/default/pages/get_help.html.tmpl
new file mode 100644
index 000000000..70ff0a12b
--- /dev/null
+++ b/extensions/BMO/template/en/default/pages/get_help.html.tmpl
@@ -0,0 +1,42 @@
+[%# 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): David Miller <justdave@bugzilla.org>
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+[% INCLUDE global/header.html.tmpl title = "Get Help with Mozilla Products" %]
+
+<div id="steps">
+<h2>Got a problem?</h2>
+
+<ul>
+<li><a href="http://www.mozilla.org/support/">Get help with your mozilla.org product</a></li>
+<li><a href="http://hendrix.mozilla.org/">Leave quick feedback</a></li>
+<li><a href="http://input.mozilla.com/feedback">Report a broken website</a></li>
+<li><a href="enter_bug.cgi">Report a [% terms.bug %]</a> - latest release only
+ [% IF NOT user.id %]
+ (you'll need an
+ <a href="createaccount.cgi">account</a>)
+ [% END %]
+</li>
+</ul>
+</div>
+
+<br>
+
+[% INCLUDE global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/pages/get_permissions.html.tmpl b/extensions/BMO/template/en/default/pages/get_permissions.html.tmpl
new file mode 100644
index 000000000..b70aa488f
--- /dev/null
+++ b/extensions/BMO/template/en/default/pages/get_permissions.html.tmpl
@@ -0,0 +1,44 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/header.html.tmpl
+ title = "Upgrade Permissions"
+%]
+
+<h3>How to apply for upgraded permissions</h3>
+
+<p>
+ If you want <kbd>canconfirm</kbd>, email <a href="mailto:bmo-perms@mozilla.org">
+ bmo-perms@mozilla.org</a> the URLs of three good [% terms.bug %] reports you have filed.
+</p>
+
+<p>
+ If you want <kbd>editbugs</kbd>, email <a href="mailto:bmo-perms@mozilla.org">
+ bmo-perms@mozilla.org</a> either:
+ <ul>
+ <li>
+ The URLs of two [% terms.bugs %] to which you have attached patches
+ or testcases; or
+ </li>
+ <li>
+ The URLs of the relevant comment on three [% terms.bugs %] which you
+ wanted to change, but couldn't, and so added a comment instead.
+ </li>
+ </ul>
+</p>
+
+<p>
+ <kbd>editbugs</kbd> implies <kbd>canconfirm</kbd>; there's no need to apply for both.
+</p>
+
+<p>
+ Don't forget to include your [% terms.Bugzilla %] ID if it's not the email address
+ you are emailing from.
+</p>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/pages/group_admins.html.tmpl b/extensions/BMO/template/en/default/pages/group_admins.html.tmpl
new file mode 100644
index 000000000..01bb744c4
--- /dev/null
+++ b/extensions/BMO/template/en/default/pages/group_admins.html.tmpl
@@ -0,0 +1,54 @@
+[%# 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 BMO 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):
+ # David Lawrence <dkl@mozilla.com>
+ #%]
+
+[% INCLUDE global/header.html.tmpl
+ title = "Group Admins Report"
+ style_urls = [ "extensions/BMO/web/styles/reports.css" ]
+ yui = [ "datasource" ]
+%]
+
+[% IF groups.size > 0 %]
+ <table border="0" cellspacing="0" id="report" class="hover" width="100%">
+ <tr id="report-header">
+ <th align="left">Name</th>
+ <th align="left">Admins</th>
+ </tr>
+
+ [% FOREACH group = groups %]
+ [% count = loop.count() %]
+ <tr class="report_item [% count % 2 == 1 ? "report_row_odd" : "report_row_even" %]">
+ <td>
+ [% group.name FILTER html %]
+ </td>
+ <td>
+ [% FOREACH admin = group.admins %]
+ [% INCLUDE global/user.html.tmpl who = admin %][% ", " UNLESS loop.last %]
+ [% END %]
+ </td>
+ </tr>
+ [% END %]
+ </table>
+[% ELSE %]
+ <p>
+ No groups found.
+ </p>
+[% END %]
+
+[% INCLUDE global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/pages/group_members.html.tmpl b/extensions/BMO/template/en/default/pages/group_members.html.tmpl
new file mode 100644
index 000000000..daf4d5b0d
--- /dev/null
+++ b/extensions/BMO/template/en/default/pages/group_members.html.tmpl
@@ -0,0 +1,97 @@
+[%# 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.
+ #%]
+
+[% INCLUDE global/header.html.tmpl
+ title = "Group Members Report"
+ style_urls = [ "extensions/BMO/web/styles/reports.css" ]
+%]
+
+<form method="GET" action="page.cgi">
+ <input type="hidden" name="id" value="group_members.html">
+
+ <table id="parameters">
+ <tr>
+ <th>Group</th>
+ <td>
+ <select name="group">
+ [% FOREACH group_name = groups %]
+ <option value="[% group_name FILTER html %]"
+ [% "selected" IF group_name == group %]>
+ [% group_name FILTER html %]</option>
+ [% END %]
+ </select>
+ <input type="checkbox" name="include_disabled" id="include_disabled"
+ value="1" [% "checked" IF include_disabled %]>
+ <label for="include_disabled">
+ Include disabled users
+ </label>
+ <input type="submit" value="Generate">
+ </td>
+ </tr>
+ </table>
+</form>
+
+[% IF group != '' %]
+
+ <p>
+ Members of the <b>[% group FILTER html %]</b> group:
+ </p>
+
+ [% IF types.size > 0 %]
+ <table border="0" cellspacing="0" id="report" class="nohover" width="100%">
+ <tr id="report-header">
+ <th>Type</th>
+ <th>Count</th>
+ <th>Members</th>
+ <th class="right">Last Seen (days ago)</th>
+ </tr>
+
+ [% FOREACH type = types %]
+ [% count = loop.count() %]
+ <tr class="report_item [% count % 2 == 1 ? "report_row_odd" : "report_row_even" %]">
+ <td valign="top">
+ [% "via&nbsp;" UNLESS type.name == 'direct' %]
+ [% type.name FILTER html %]
+ </td>
+ <td valign="top" align="right">
+ [% type.members.size FILTER html %]
+ </td>
+ <td valign="top" width="100%" colspan="2">
+ <table cellspacing="0" class="hoverrow">
+ [% FOREACH member = type.members %]
+ <tr>
+ <td width="100%">
+ <a href="editusers.cgi?action=edit&amp;userid=[% member.id FILTER none %]"
+ target="_blank">
+ <span [% 'class="bz_inactive"' UNLESS member.is_enabled %]>
+ [% member.name FILTER html %] &lt;[% member.email FILTER email FILTER html %]&gt;
+ </span>
+ </a>
+ </td>
+ <td align="right" nowrap>
+ [% member.lastseen FILTER html %]
+ </td>
+ </tr>
+ [% END %]
+ </table>
+ </td>
+ </tr>
+ [% END %]
+ </table>
+
+ <a href="page.cgi?id=group_members.json&amp;group=[% group FILTER uri %]
+ [% IF include_disabled %]&amp;include_disabled=1[% END %]">JSON</a>
+ [% ELSE %]
+ <p>
+ <i>This group is empty.</i>
+ </p>
+ [% END %]
+
+[% END %]
+
+[% INCLUDE global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/pages/group_members.json.tmpl b/extensions/BMO/template/en/default/pages/group_members.json.tmpl
new file mode 100644
index 000000000..8cbb2a23a
--- /dev/null
+++ b/extensions/BMO/template/en/default/pages/group_members.json.tmpl
@@ -0,0 +1,32 @@
+[%# 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.
+ #%]
+
+[
+ [% SET count = 0 %]
+ [% FOREACH type = types %]
+ [% SET count = count + type.members.size %]
+ [% END %]
+ [% SET i = 0 %]
+ [% FOREACH type = types %]
+ [% FOREACH member = type.members %]
+ [% SET i = i + 1 %]
+ { "login": "[% member.login FILTER email FILTER js %]",
+ [% IF type.name == "direct" %]
+ "membership": "direct",
+ [% ELSE %]
+ "membership": "indirect",
+ "group": "[% type.name FILTER js %]",
+ [% END %]
+ [% IF include_disabled %]
+ "disabled": "[% member.is_enabled ? "false" : "true" %]",
+ [% END %]
+ "lastseen": "[% member.lastseen FILTER js %]"
+ }[% "," UNLESS i == count %]
+ [% END %]
+ [% END %]
+]
diff --git a/extensions/BMO/template/en/default/pages/group_membership.html.tmpl b/extensions/BMO/template/en/default/pages/group_membership.html.tmpl
new file mode 100644
index 000000000..32484b13f
--- /dev/null
+++ b/extensions/BMO/template/en/default/pages/group_membership.html.tmpl
@@ -0,0 +1,75 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/header.html.tmpl
+ title = "Group Membership Report"
+ yui = [ 'autocomplete' ]
+ style_urls = [ "extensions/BMO/web/styles/reports.css" ]
+ javascript_urls = [ "js/field.js" ]
+%]
+
+<form method="GET" action="page.cgi">
+<input type="hidden" name="id" id="id" value="group_membership.html">
+
+<table id="parameters">
+<tr>
+ <th>User(s):</th>
+ <td>
+ [% INCLUDE global/userselect.html.tmpl
+ id => "who"
+ name => "who"
+ value => who.join(', ')
+ size => 40
+ classes => ["bz_userfield"]
+ multiple => 5
+ field_title => "One or more email address (comma delimited)"
+ %]
+ </td>
+ <td>&nbsp;</td>
+ <td>
+ <select name="output"
+ onchange="document.getElementById('id').value = 'group_membership.' + this.value">
+ <option value="html" [% 'selected' IF output == 'html' %]>HTML</option>
+ <option value="txt" [% 'selected' IF output == 'txt' %]>Text</option>
+ </select>
+ </td>
+ <td>
+ <input type="submit" value="Generate">
+ </td>
+</tr>
+</table>
+
+</form>
+
+[% IF users.size %]
+
+ <table border="0" cellspacing="0" id="report" class="hover" width="100%">
+ [% FOREACH u = users %]
+ <tr>
+ <th colspan="3">[% u.user.identity FILTER html %]</th>
+ </tr>
+ [% FOREACH g = u.groups %]
+ <tr>
+ <td>&nbsp;</td>
+ <td>[% g.name FILTER html %]</td>
+ <td>[% g.desc FILTER html %]</td>
+ <td>
+ [% IF g.via == '' %]
+ direct
+ [% ELSE %]
+ <i>[% g.via FILTER html %]</i>
+ [% END %]
+ </td>
+ </tr>
+ [% END %]
+ [% END %]
+ </table>
+
+[% END %]
+
+[% INCLUDE global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/pages/group_membership.txt.tmpl b/extensions/BMO/template/en/default/pages/group_membership.txt.tmpl
new file mode 100644
index 000000000..9958f0877
--- /dev/null
+++ b/extensions/BMO/template/en/default/pages/group_membership.txt.tmpl
@@ -0,0 +1,16 @@
+[%# 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.
+ #%]
+
+[% FOREACH u = users %]
+[% u.user.login FILTER none%]:
+ [% FOREACH g = u.groups %]
+ [% g.name FILTER none %]
+ [% ',' UNLESS loop.last %]
+ [% END %]
+ [% "\n" %]
+[% END %]
diff --git a/extensions/BMO/template/en/default/pages/product_security_report.html.tmpl b/extensions/BMO/template/en/default/pages/product_security_report.html.tmpl
new file mode 100644
index 000000000..f5e1c05c8
--- /dev/null
+++ b/extensions/BMO/template/en/default/pages/product_security_report.html.tmpl
@@ -0,0 +1,60 @@
+[%# 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.
+ #%]
+
+[% INCLUDE global/header.html.tmpl
+ title = "Product Security Report"
+ style_urls = [ "extensions/BMO/web/styles/reports.css" ]
+%]
+
+<table border="0" cellspacing="0" id="report" class="nohover" width="100%">
+ <tr id="report-header">
+ <th>Product</th>
+ <th>Default Security Group</th>
+ <th>Default Group Visibility</th>
+ <th>mozilla-employee-confidential Enabled</th>
+ </tr>
+
+ [% count = 0 %]
+ [% FOREACH product = products %]
+ [% count = count + 1 %]
+ <tr class="report_item [% count % 2 == 1 ? "report_row_odd" : "report_row_even" %]">
+ <td>
+ <a href="editproducts.cgi?action=editgroupcontrols&product=[% product.name FILTER uri %]" target="_blank">
+ [% product.name FILTER html %]
+ </a>
+ </td>
+ [% IF product.group_problem %]
+ <td class="problem">
+ <span title="[% product.group_problem FILTER html %]">
+ [% product.default_security_group FILTER html %]
+ </span>
+ </td>
+ [% ELSE %]
+ <td>
+ [% product.default_security_group FILTER html %]
+ </td>
+ [% END %]
+ [% IF product.visibility_problem %]
+ <td class="problem">
+ <span title="[% product.visibility_problem FILTER html %]">
+ [% product.group_visibility FILTER html %]
+ </span>
+ </td>
+ [% ELSE %]
+ <td>
+ [% product.group_visibility FILTER html %]
+ </td>
+ [% END %]
+ <td>
+ [% product.moco ? 'Yes' : 'No' FILTER none %]
+ </td>
+ </tr>
+ [% END %]
+</table>
+
+[% INCLUDE global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/pages/query_database.html.tmpl b/extensions/BMO/template/en/default/pages/query_database.html.tmpl
new file mode 100644
index 000000000..97f5c0a25
--- /dev/null
+++ b/extensions/BMO/template/en/default/pages/query_database.html.tmpl
@@ -0,0 +1,47 @@
+[%# 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.
+ #%]
+
+[% INCLUDE global/header.html.tmpl
+ title = "Query Database"
+ style_urls = [ "extensions/BMO/web/styles/reports.css" ]
+%]
+
+<form method="post" action="page.cgi">
+<input type="hidden" name="id" value="query_database.html">
+<textarea cols="80" rows="10" name="query">[% query FILTER html %]</textarea><br>
+<input type="submit" value="Execute">
+</form>
+
+[% IF executed %]
+ <hr>
+
+ [% IF sql_error %]
+ <b>[% sql_error FILTER html %]</b>
+ [% ELSIF rows.size %]
+ <table border="0" cellspacing="0" id="report">
+ <tr>
+ [% FOREACH column = columns %]
+ <th>[% column FILTER html %]</th>
+ [% END %]
+ </tr>
+ [% FOREACH row = rows %]
+ [% tr_class = loop.count % 2 ? 'report_row_even' : 'report_row_odd' %]
+ <tr class="[% tr_class FILTER html %]">
+ [% FOREACH field = row %]
+ <td>[% field FILTER html %]</td>
+ [% END %]
+ </tr>
+ [% END %]
+ </table>
+ [% ELSE %]
+ <i>no results</i>
+ [% END %]
+
+[% END %]
+
+[% INCLUDE global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/pages/release_tracking_report.html.tmpl b/extensions/BMO/template/en/default/pages/release_tracking_report.html.tmpl
new file mode 100644
index 000000000..71228014a
--- /dev/null
+++ b/extensions/BMO/template/en/default/pages/release_tracking_report.html.tmpl
@@ -0,0 +1,103 @@
+[%# 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.
+ #%]
+
+[% INCLUDE global/header.html.tmpl
+ title = "Release Tracking Report"
+ style_urls = [ "extensions/BMO/web/styles/reports.css" ]
+ javascript_urls = [ "extensions/BMO/web/js/release_tracking_report.js" ]
+%]
+
+<noscript>
+<h1>JavaScript is required to use this report.</h1>
+</noscript>
+
+<script>
+var flags_data = [% flags_json FILTER none %];
+var products_data = [% products_json FILTER none %];
+var fields_data = [% fields_json FILTER none %];
+var default_query = '[% default_query FILTER js %]';
+</script>
+
+<form action="page.cgi" method="get" onSubmit="return onFormSubmit()">
+<input type="hidden" name="id" value="release_tracking_report.html">
+<input type="hidden" name="q" id="q" value="">
+<table>
+
+<tr>
+ <th>Approval:</th>
+ <td>
+ Show [% terms.bugs %] where
+ <select id="flag" onChange="onFlagChange()">
+ [% FOREACH flag_name = flag_names %]
+ <option value="[% flag_name FILTER html %]">[% flag_name FILTER html %]</option>
+ [% END %]
+ </select>
+
+ was changed to (and is currently)
+ <select id="flag_value">
+ <option value="?">?</option>
+ <option value="-">-</option>
+ <option value="+">+</option>
+ </select>
+
+ between
+ <select id="range" onChange="serialiseForm()">
+ [% FOREACH range = ranges %]
+ <option value="[% range.value FILTER html %]">
+ [% range.label FILTER html %]
+ </option>
+ [% END %]
+ </select>
+ </td>
+</tr>
+
+<tr>
+ <th>Status:</th>
+ <td>
+ for the product
+ <select id="product" onChange="onProductChange()">
+ </select>
+ </td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+ <td>
+ <select id="op" onChange="serialiseForm()">
+ <option value="and">All selected tracking fields (AND)</option>
+ <option value="or">Any selected tracking fields (OR)</option>
+ </select>
+ [
+ <a href="javascript:void(0)" onClick="selectAllFields()">All</a> |
+ <a href="javascript:void(0)" onClick="selectNoFields()">None</a>
+ ]
+ [
+ <a href="javascript:void(0)" onClick="invertFields()">Invert</a>
+ ]
+ <br>
+ <span id="tracking_span">
+ </span>
+ </td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+ <td colspan="2">
+ <input type="submit" value="Search">
+ <input type="submit" value="Reset" onClick="onFormReset(); return false">
+ <a href="?" id="bookmark">Bookmarkable Link</a>
+ </td>
+</tr>
+</table>
+</form>
+
+<p>
+ <i>"fixed" in the status field checks for the "verified" status as well as "fixed".</i>
+</p>
+
+[% INCLUDE global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/pages/triage_reports.html.tmpl b/extensions/BMO/template/en/default/pages/triage_reports.html.tmpl
new file mode 100644
index 000000000..a7f26e86d
--- /dev/null
+++ b/extensions/BMO/template/en/default/pages/triage_reports.html.tmpl
@@ -0,0 +1,199 @@
+[%# 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 BMO 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>
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% js_data = BLOCK %]
+var useclassification = false;
+var first_load = true;
+var last_sel = [];
+var cpts = new Array();
+[% n = 1 %]
+[% FOREACH p = user.get_selectable_products %]
+ cpts['[% n FILTER js %]'] = [
+ [%- FOREACH c = p.components %]'[% c.name FILTER js %]'[% ", " UNLESS loop.last %] [%- END -%] ];
+ [% n = n+1 %]
+[% END %]
+
+var selected_components = [
+ [%- FOREACH c = input.component %]'[% c FILTER js %]'
+ [%- ',' UNLESS loop.last %] [%- END ~%] ];
+
+[% END %]
+
+[% INCLUDE global/header.html.tmpl
+ title = "Triage Reports"
+ yui = [ 'autocomplete', 'calendar' ]
+ javascript = js_data
+ javascript_urls = [ "js/util.js", "js/field.js", "js/productform.js",
+ "extensions/BMO/web/js/triage_reports.js" ]
+ style_urls = [ "skins/standard/buglist.css",
+ "extensions/BMO/web/styles/triage_reports.css" ]
+%]
+
+<noscript>
+<h2>Javascript is required to use this report.</h2>
+</noscript>
+
+[% PROCESS "global/field-descs.none.tmpl" %]
+
+<form id="activity_form" name="activity_form" action="page.cgi" method="get"
+ onSubmit="return onGenerateReport()">
+<input type="hidden" name="id" value="triage_reports.html">
+<input type="hidden" name="action" value="run">
+
+Show UNCONFIRMED [% terms.bugs %] with:
+<table id="triage_form">
+
+<tr>
+ <th>Product:</th>
+ <td>
+ <select name="product" id="product" onChange="onSelectProduct()">
+ <option value=""></option>
+ [% FOREACH p = user.get_selectable_products %]
+ <option value="[% p.name FILTER html %]"
+ [% " selected" IF input.product == p.name %]>
+ [% p.name FILTER html %]
+ </option>
+ [% END %]
+ </select>
+ </td>
+ <td rowspan="2" valign="top">
+ <b>Comment:</b><br>
+
+ <input type="checkbox" name="filter_commenter" id="filter_commenter" value="1"
+ [% 'checked' IF input.filter_commenter %]>
+ <label for="filter_commenter">where the last commenter</label>
+ <select name="commenter" id="commenter" onChange="onCommenterChange()">
+ <option value="reporter" [% 'selected' IF input.commenter == 'reporter' %]>is the reporter</option>
+ <option value="noconfirm" [% 'selected' IF input.commenter == 'noconfirm' %]>does not have canconfirm</option>
+ <option value="is" [% 'selected' IF input.commenter == 'is' %]>is</option>
+ </select>
+ [%+ INCLUDE global/userselect.html.tmpl
+ id => "commenter_is"
+ name => "commenter_is"
+ value => input.commenter_is
+ size => 20
+ emptyok => 0
+ classes = input.commenter == "is" ? "" : "hidden"
+ %]
+ <br>
+
+ <input type="checkbox" name="filter_last" id="filter_last" value="1"
+ [% 'checked' IF input.filter_last %]>
+ <label for="filter_last">where the last comment is older than</label>
+ <select name="last" id="last" onChange="onLastChange()">
+ <option value="30" [% 'selected' IF input.last == '30' %]>30 days</option>
+ <option value="60" [% 'selected' IF input.last == '60' %]>60 days</option>
+ <option value="90" [% 'selected' IF input.last == '90' %]>90 days</option>
+ <option value="365" [% 'selected' IF input.last == '365' %]>one year</option>
+ <option value="is" [% 'selected' IF input.last == 'is' %]>the date</option>
+ </select>
+ <span id="last_is_span" class="[% 'hidden' IF input.last != 'is' %]">
+ <input type="text" id="last_is" name="last_is" size="11" maxlength="10"
+ value="[% input.last_is FILTER html %]"
+ onChange="updateCalendarLastIs(this)">
+ <button type="button" class="calendar_button" id="button_calendar_last_is"
+ onClick="showCalendar('last_is')"><span>Calendar</span>
+ </button>
+ <div id="con_calendar_last_is"></div>
+ </span>
+ <br>
+ </td>
+</tr>
+
+<tr>
+ <th>Component:</th>
+ <td>
+ <select name="component" id="component" multiple size="5">
+ </select>
+ </td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+ <td>
+ <input type="submit" value="Generate Report">
+ </td>
+</tr>
+
+</table>
+
+</form>
+<script>
+ createCalendar('last_is');
+</script>
+
+[% IF input.action == 'run' %]
+<hr>
+[% IF bugs.size > 0 %]
+ <p>
+ Found [% bugs.size %] [%+ terms.bug %][% 's' IF bugs.size != 1 %]:
+ </p>
+ <table border="0" cellspacing="0" id="report" width="100%">
+ <tr id="report-header">
+ <th>[% terms.Bug %] / Date</th>
+ <th>Summary</th>
+ <th>Reporter / Commenter</th>
+ <th>Comment Date</th>
+ <th>Last Comment</th>
+ </tr>
+
+ [% FOREACH bug = bugs %]
+ [% count = loop.count() %]
+ <tr class="bz_bugitem [% count % 2 == 1 ? "bz_row_odd" : "bz_row_even" %]">
+ <td>
+ [% bug.id FILTER bug_link(bug.id) FILTER none %]<br>
+ [% bug.creation_ts.replace(' .*' '') FILTER html FILTER no_break %]
+ </td>
+ <td>
+ [% bug.summary FILTER html %]
+ </td>
+ <td>
+ [% INCLUDE global/user.html.tmpl who = bug.reporter %]
+ [% IF bug.commenter.id != bug.reporter.id %]
+ <br>[% INCLUDE global/user.html.tmpl who = bug.commenter %]
+ [% END %]
+ </td>
+ <td>
+ [% bug.comment_ts FILTER html FILTER no_break %]
+ </td>
+ <td>
+ [% bug.comment FILTER html %]
+ </td>
+ </tr>
+ [% END %]
+ </table>
+
+ <p>
+ <a href="buglist.cgi?bug_id=
+ [%- FOREACH bug = bugs %][% bug.id FILTER uri %],[% END -%]
+ ">Show as a [% terms.Bug %] List</a>
+ </p>
+
+[% ELSE %]
+ <p>
+ No [% terms.bugs %] found.
+ </p>
+[% END %]
+
+[% END %]
+
+[% INCLUDE global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/pages/upgrade-3.6.html.tmpl b/extensions/BMO/template/en/default/pages/upgrade-3.6.html.tmpl
new file mode 100644
index 000000000..8fa944ae6
--- /dev/null
+++ b/extensions/BMO/template/en/default/pages/upgrade-3.6.html.tmpl
@@ -0,0 +1,304 @@
+[%# 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): David Miller <justdave@bugzilla.org>
+ # Reed Loden <reed@reedloden.com>
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+[% INCLUDE global/header.html.tmpl
+ title = "Bugzilla 3.6 Upgrade"
+%]
+[% USE date %]
+
+<p><b>Last Updated:</b> [% date.format(template.modtime, "%d-%b-%Y %H:%M %Z") %]</p>
+
+<p>On Friday, July 9, 2010, at 11:40pm PDT (0640 UTC), bugzilla.mozilla.org was
+ <a href="show_bug.cgi?id=558044">upgraded</a> to Bugzilla 3.6.1+. Please
+ <a href="enter_bug.cgi?product=mozilla.org&amp;component=Bugzilla:+Other+b.m.o+Issues&amp;blocked=bmo-regressions">file
+ any regressions</a> for tracking purposes.</p>
+
+<h3>Known Issues</h3>
+
+<p>The following is a list of issues which are known to be broken or incomplete with this upgrade so far.</p>
+
+<ul>
+
+<li>The <a href="https://bugzilla.mozilla.org/showdependencytree.cgi?id=577801&hide_resolved=1">stuff filed in Bugzilla</a>.</li>
+
+</ul>
+
+<h3>What's New</h3>
+
+<h4>Custom bugzilla.mozilla.org Changes</h4>
+
+<ul>
+ <li>Addition of autocomplete support for all user-related fields (assignee,
+ QA contact, and CC list) and the keywords field.</li>
+ <li>New attachment details UI.</li>
+ <li>New icons for the front page.</li>
+ <li>Removal of unused "Patches" column from buglist.</li>
+ <li>Initial support for <a href="http://en.wikipedia.org/wiki/Strict_Transport_Security">Strict-Transport-Security</a> (STS) header.</li>
+</ul>
+
+<h4>General Usability Improvements</h4>
+
+<p>A <a href="https://wiki.mozilla.org/Bugzilla:CMU_HCI_Research_2008">scientific
+ usability study</a> was done on [% terms.Bugzilla %] by researchers
+ from Carnegie-Mellon University. As a result of this study,
+ <a href="https://bugzilla.mozilla.org/showdependencytree.cgi?id=490786&amp;hide_resolved=0">several
+ usability issues</a> were prioritized to be fixed, based on specific data
+ from the study.</p>
+
+<p>As a result, you will see many small improvements in [% terms.Bugzilla %]'s
+ usability, such as using Javascript to validate certain forms before
+ they are submitted, standardizing the words that we use in the user interface,
+ being clearer about what [% terms.Bugzilla %] needs from the user,
+ and other changes, all of which are also listed individually in this New
+ Features section.</p>
+
+<p>Work continues on improving usability for the next release of
+ [%+ terms.Bugzilla %], but the results of the research have already
+ had an impact on this 3.6 release.</p>
+
+<h4>Improved Quicksearch</h4>
+
+<p>The "quicksearch" box that appears on the front page of
+ [%+ terms.Bugzilla %] and in the header/footer of every page
+ is now simplified and made more powerful. There is a
+ <kbd>[?]</kbd> link next to the box that will take you to
+ the simplified <a href="page.cgi?id=quicksearch.html">Quicksearch Help</a>,
+ which describes every single feature of the system in a simple layout,
+ including new features such as the ability to use partial field names
+ when searching.</p>
+
+<p>Quicksearch should also be much faster than it was before, particularly
+ on large installations.</p>
+
+<p>Note that in order to implement the new quicksearch, certain old
+ and rarely-used features had to be removed:
+
+<ul>
+ <li><b>+</b> as a prefix to mean "search additional resolutions", and
+ <b>+</b> as a prefix to mean "search just the summary". You can
+ instead use <kbd>summary:</kbd> to explicitly search summaries.</li>
+ <li>Searching the Severity field if you type something that matches
+ the first few characters of a severity. You can explicitly search
+ the Severity field if you want to find [% terms.bugs %] by severity.</li>
+ <li>Searching the Priority field if you typed something that exactly
+ matched the name of a priority. You can explicitly search the
+ Priority field if you want to find [% terms.bugs %] by priority.</li>
+ <li>Searching the Platform and OS fields if you typed in one of a
+ certain hard-coded list of strings (like "pc", "windows", etc.).
+ You can explicitly search these fields, instead, if you want to
+ find [% terms.bugs %] with a specific Platform or OS set.</li>
+</ul>
+
+<h4>Simple "Browse" Interface</h4>
+
+<p>There is now a "Browse" link in the header of each [% terms.Bugzilla %]
+ page that presents a very basic interface that allows users to simply
+ browse through all open [% terms.bugs %] in particular components.</p>
+
+<h4>JSON-RPC Interface</h4>
+
+<p>[% terms.Bugzilla %] now has support for the
+ <a href="http://json-rpc.org/">JSON-RPC</a> WebServices protocol via
+ <a href="[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Server/JSONRPC.html">jsonrpc.cgi</a>.
+ The JSON-RPC interface is experimental in this release--if you want any
+ fundamental changes in how it works,
+ <a href="http://www.bugzilla.org/developers/reporting_bugs.html">let us
+ know</a>, for the next release of [% terms.Bugzilla %].</p>
+
+<h3>New Features</h3>
+
+<h4>Enhancements for Users</h4>
+
+<ul>
+ <li><b>[% terms.Bug %] Filing:</b> When filing [% terms.abug %],
+ [%+ terms.Bugzilla %] now visually indicates which fields are
+ mandatory.</li>
+ <li><b>[% terms.Bug %] Filing:</b> "Bookmarkable templates" now
+ support the "alias" and "estimated hours" fields.</li>
+
+ <li><b>[% terms.Bug %] Editing:</b> In previous versions of
+ [%+ terms.Bugzilla %], if you added a private comment to [% terms.abug %],
+ then <em>none</em> of the changes that you made at that time were
+ sent to users who couldn't see the private comment. Now, for users
+ who can't see private comments, public changes are sent, but the private
+ comment is excluded from their email notification.</li>
+ <li><b>[% terms.Bug %] Editing:</b> The controls for groups now
+ appear to the right of the attachment and time-tracking tables,
+ when editing [% terms.abug %].</li>
+ <li><b>[% terms.Bug %] Editing:</b> The "Collapse All Comments"
+ and "Expand All Comments" links now appear to the right of the
+ comment list instead of above it.</li>
+ <li><b>[% terms.Bug %] Editing:</b> The See Also field now supports
+ URLs for Google Code Issues and the Debian B[% %]ug-Tracking System.</li>
+ <li><b>[% terms.Bug %] Editing:</b> There have been significant performance
+ improvements in <kbd>show_bug.cgi</kbd> (the script that displays the
+ [% terms.bug %]-editing form), particularly for [% terms.bugs %] that
+ have lots of comments or attachments.</li>
+
+ <li><b>Attachments:</b> The "Details" page of an attachment
+ now displays itself as uneditable if you can't edit the fields
+ there.</li>
+ <li><b>Attachments:</b> We now make sure that there is
+ a Description specified for an attachment, using JavaScript, before
+ the form is submitted.</li>
+ <li><b>Attachments:</b> There is now a link back to the [% terms.bug %]
+ at the bottom of the "Details" page for an attachment.</li>
+ <li><b>Attachments:</b> When you click on an "attachment 12345" link
+ in a comment, if the attachment is a patch, you will now see the
+ formatted "Diff" view instead of the raw patch.</li>
+ <li><b>Attachments</b>: For text attachments, we now let the browser
+ auto-detect the character encoding, instead of forcing the browser to
+ always assume the attachment is in UTF-8.</li>
+
+ <li><b>Search:</b> You can now display [% terms.bug %] flags as a column
+ in search results.</li>
+ <li><b>Search:</b> When viewing search results, you can see which columns are
+ being sorted on, and which direction the sort is on, as indicated
+ by arrows next to the column headers.</li>
+ <li><b>Search:</b> You can now search the Deadline field using relative
+ dates (like "1d", "2w", etc.).</li>
+ <li><b>Search:</b> The iCalendar format of search results now includes
+ a PRIORITY field.</li>
+ <li><b>Search:</b> It is no longer an error to enter an invalid search
+ order in a search URL--[% terms.Bugzilla %] will simply warn you that
+ some of your order options are invalid.</li>
+ <li><b>Search:</b> When there are no search results, some helpful
+ links are displayed, offering actions you might want to take.</li>
+ <li><b>Search:</b> For those who like to make their own
+ <kbd>buglist.cgi</kbd> URLs (and for people working on customizations),
+ <kbd>buglist.cgi</kbd> now accepts nearly every valid field in
+ [%+ terms.Bugzilla %] as a direct URL parameter, like
+ <kbd>&amp;field=value</kbd>.</li>
+
+ <li><b>Requests:</b> When viewing the "My Requests" page, you can now
+ see the lists as a normal search result by clicking a link at the
+ bottom of each table.</li>
+ <li><b>Requests:</b> When viewing the "My Requests" page, if you are
+ using Classifications, the Product drop-down will be grouped by
+ Classification.</li>
+
+ <li>If there are multiple languages available for your
+ [%+ terms.Bugzilla %], you can now select what language you want
+ [%+ terms.Bugzilla %] displayed in using links at the top of every
+ page.</li>
+ <li>When creating a new account, you will be automatically logged in
+ after setting your password.</li>
+ <li>There is no longer a maximum password length for accounts.</li>
+ <li>In the Dusk skin, it's now easier to see links.</li>
+ <li>In the Whining system, you can now choose to receive emails even
+ if there are no [% terms.bugs %] that match your searches.</li>
+ <li>The arrows in dependency graphs now point the other way, so that
+ [%+ terms.bugs %] point at their dependencies.</li>
+
+ <li><b>New Charts:</b> You can now convert an existing Saved Search
+ into a data series for New Charts.</li>
+ <li><b>New Charts:</b> There is now an interface that allows you to
+ delete data series.</li>
+ <li><b>New Charts:</b> When deleting a product, you now have the option
+ to delete the data series that are associated with that product.</li>
+</ul>
+
+<h4>Enhancements for Administrators and Developers</h4>
+
+<ul>
+ <li>Depending on how your workflow is set up, it is now possible to
+ have both UNCONFIRMED and REOPENED show up as status choices for
+ a closed [% terms.bug %]. If you only want one or the other to
+ show up, you should edit your status workflow appropriately
+ (possibly by removing or disabling the REOPENED status).</li>
+ <li>You can now "disable" field values so that they don't show
+ up as choices on [% terms.abug %] unless they are already set as
+ the value for that [% terms.bug %]. This doesn't work for the
+ per-product field values (component, target_milestone, and version)
+ yet, though.</li>
+ <li>Users are now locked out of their accounts for 30 minutes after
+ trying five bad passwords in a row during login. Every time a
+ user is locked out like this, the user in the "maintainer" parameter
+ will get an email.</li>
+ <li>The minimum length allowed for a password is now 6 characters.</li>
+ <li>The <kbd>UNCONFIRMED</kbd> status being enabled in a product
+ is now unrelated to the voting parameters. Instead, there is a checkbox
+ to enable the <kbd>UNCONFIRMED</kbd> status in a product.</li>
+ <li>Information about duplicates is now stored in the database instead
+ of being stored in the <kbd>data/</kbd> directory. On large installations
+ this could save several hundred megabytes of disk space.</li>
+
+ <li>When editing a group, you can now specify that members of a group
+ are allowed to grant others membership in that group itself.</li>
+ <li>The ability to compress BMP attachments to PNGs is now an Extension.
+ To enable the feature, remove the file
+ <kbd>extensions/BmpConvert/disabled</kbd> and then run checksetup.pl.</li>
+ <li>The default list of values for the Priority field are now clear English
+ words instead of P1, P2, etc.</li>
+ <li><kbd>config.cgi</kbd> now returns an ETag header and understands
+ the If-None-Match header in HTTP requests.</li>
+ <li>The XML format of <kbd>show_bug.cgi</kbd> now returns more information:
+ the numeric id of each comment, whether an attachment is a URL,
+ the modification time of an attachment, the numeric id of a flag,
+ and the numeric id of a flag's type.</li>
+</ul>
+
+<h4>WebService Changes</h4>
+
+<ul>
+ <li>The WebService now returns all dates and times in the UTC timezone.
+ <kbd>B[% %]ugzilla.time</kbd> now acts as though the [% terms.Bugzilla %]
+ server were in the UTC timezone, always. If you want to write clients
+ that are compatible across all [% terms.Bugzilla %] versions,
+ check the timezone from <kbd>B[% %]ugzilla.timezone</kbd> or
+ <kbd>B[% %]ugzilla.time</kbd>, and always input times in that timezone
+ and expect times to be returned in that format.</li>
+ <li>You can now log in by passing <kbd>Bugzilla_login</kbd> and
+ <kbd>Bugzilla_password</kbd> as arguments to any WebService function.
+ See the
+ <a href="[% docs_urlbase FILTER html %]api/Bugzilla/WebService.html#LOGGING_IN">Bugzilla::WebService</a>
+ documentation for details.</li>
+ <li>New Method:
+ <a href="[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Bug.html#attachments">B[% %]ug.attachments</a>
+ which allows getting information about attachments.</li>
+ <li>New Method:
+ <a href="[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Bug.html#fields">B[% %]ug.fields</a>,
+ which gets information about all the fields that [% terms.abug %] can have
+ in [% terms.Bugzilla %], include custom fields and legal values for
+ all fields. The <kbd>B[% %]ug.legal_values</kbd> method is now deprecated.</li>
+ <li>In the <kbd>B[% %]ug.add_comment</kbd> method, the "private" parameter
+ has been renamed to "is_private" (for consistency with other methods).
+ You can still use "private", though, for backwards-compatibility.</li>
+ <li>The WebService now has Perl's "taint mode" turned on. This means that
+ it validates all data passed in before sending it to the database.
+ Also, all parameter names are validated, and if you pass in a parameter
+ whose name contains anything other than letters, numbers, or underscores,
+ that parameter will be ignored. Mostly this just affects
+ customizers--[% terms.Bugzilla %]'s WebService is not functionally
+ affected by these changes.</li>
+ <li>In previous versions of [% terms.Bugzilla %], error messages were
+ sent word-wrapped to the client, from the WebService. Error messages
+ are now sent as one unbroken line.</li>
+</ul>
+
+<h3>Last Ten Commits</h3>
+
+<pre>[% bzr_history.join('') FILTER html %]</pre>
+
+<br>
+
+[% INCLUDE global/footer.html.tmpl %]
diff --git a/extensions/BMO/template/en/default/pages/user_activity.html.tmpl b/extensions/BMO/template/en/default/pages/user_activity.html.tmpl
new file mode 100644
index 000000000..c9b46b2eb
--- /dev/null
+++ b/extensions/BMO/template/en/default/pages/user_activity.html.tmpl
@@ -0,0 +1,230 @@
+[%# 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 who %]
+[% who_title = ' (' _ who _ ')' %]
+[% ELSE %]
+[% who_title = '' %]
+[% END %]
+
+[% INCLUDE global/header.html.tmpl
+ title = "User Activity Report" _ who_title
+ yui = [ 'autocomplete', 'calendar' ]
+ javascript_urls = [ "js/util.js", "js/field.js" ]
+ style_urls = [ "extensions/BMO/web/styles/reports.css" ]
+
+%]
+
+[% PROCESS "global/field-descs.none.tmpl" %]
+[% PROCESS bug/time.html.tmpl %]
+
+<form id="activity_form" name="activity_form" action="page.cgi" method="get">
+<input type="hidden" name="id" value="user_activity.html">
+<input type="hidden" name="action" value="run">
+<table id="parameters">
+
+<tr>
+ <th>
+ Who:
+ </th>
+ <td>
+ [% INCLUDE global/userselect.html.tmpl
+ id => "who"
+ name => "who"
+ value => who
+ size => 40
+ emptyok => 0
+ title => "One or more email address (comma delimited)"
+ %]
+ &nbsp;
+ </td>
+ <th>
+ Period:
+ </th>
+ <td>
+ <input type="text" id="from" name="from" size="11"
+ align="right" value="[% from FILTER html %]" maxlength="10"
+ onchange="updateCalendarFromField(this)">
+ <button type="button" class="calendar_button" id="button_calendar_from"
+ onclick="showCalendar('from')"><span>Calendar</span>
+ </button>
+ <div id="con_calendar_from"></div>
+ to
+ <input type="text" name="to" size="11" id="to"
+ align="right" value ="[% to FILTER html %]" maxlength="10"
+ onchange="updateCalendarFromField(this)">
+ <button type="button" class="calendar_button" id="button_calendar_to"
+ onclick="showCalendar('to')"><span>Calendar</span>
+ </button>
+ <div id="con_calendar_to"></div>
+ </td>
+ <th>
+ Group by:
+ </th>
+ <td>
+ <select name="group">
+ <option value="when" [% 'selected' IF group == 'when' %]>When</option>
+ <option value="bug" [% 'selected' IF group == 'bug' %]>[% terms.Bug %]</option>
+ </select>
+ </td>
+ <td>
+ <input type="submit" id="run" value="Generate Report">
+ </td>
+</tr>
+
+</table>
+[% IF debug_sql %]
+ <input type="hidden" name="debug" value="1">
+[% END %]
+</form>
+
+<script type="text/javascript">
+ createCalendar('from');
+ createCalendar('to');
+</script>
+
+[% IF action == 'run' %]
+
+[% IF debug_sql %]
+ <pre>[% debug_sql FILTER html %]</pre>
+[% END %]
+
+[% IF incomplete_data %]
+ <p>
+ There used to be an issue in <a href="http://www.bugzilla.org/">Bugzilla</a>
+ which caused activity data to be lost if there were a large number of cc's
+ or dependencies. That has been fixed, but some data was already lost in
+ your activity table that could not be regenerated. The changes that
+ could not reliably determine are prefixed by '?'.
+ </p>
+[% END %]
+
+[% IF operations.size > 0 %]
+ <br>
+ <table border="1" cellpadding="4" cellspacing="0" id="report" class="hover">
+ <tr id="report-header">
+ [% IF who_count > 1 %]
+ <th>Who</th>
+ [% END %]
+ [% IF group == 'when' %]
+ <th class="sorted">[% INCLUDE group_when_link %]</th>
+ <th>[% INCLUDE group_bug_link %]</th>
+ [% ELSE %]
+ <th class="sorted">[% INCLUDE group_bug_link %]</th>
+ <th>[% INCLUDE group_when_link %]</th>
+ [% END %]
+ <th>What</th>
+ <th>Removed</th>
+ <th>Added</th>
+ </tr>
+
+ [% FOREACH operation = operations %]
+ [% tr_class = loop.count % 2 ? 'report_row_even' : 'report_row_odd' %]
+ [% FOREACH change = operation.changes %]
+ <tr class="[% tr_class FILTER none %]">
+ [% IF loop.count == 1 %]
+ [% IF who_count > 1 %]
+ <td>[% operation.who FILTER email FILTER html %]</td>
+ [% END %]
+ [% IF group == 'when' %]
+ <td>[% change.when FILTER time FILTER no_break %]</td>
+ <td>[% operation.bug FILTER bug_link(operation.bug) FILTER none %]</td>
+ [% ELSE %]
+ <td>[% operation.bug FILTER bug_link(operation.bug) FILTER none %]</td>
+ <td>[% change.when FILTER time FILTER no_break %]</td>
+ [% END %]
+ [% ELSE %]
+ [% IF who_count > 1 %]
+ <td>&nbsp;</td>
+ [% END %]
+ <td>&nbsp;</td>
+ [% IF group == 'when' %]
+ <td>&nbsp;</td>
+ [% ELSE %]
+ <td>[% change.when FILTER time FILTER no_break %]</td>
+ [% END %]
+ [% END %]
+ <td>
+ [% IF change.attachid %]
+ <a href="attachment.cgi?id=[% change.attachid FILTER uri %]"
+ title="[% change.attach.description FILTER html %]
+ [%- %] - [% change.attach.filename FILTER html %]"
+ >Attachment #[% change.attachid FILTER html %]</a>
+ [% END %]
+ [%IF change.comment.defined && change.fieldname == 'longdesc' %]
+ [% "Comment $change.comment.count"
+ FILTER bug_link(operation.bug, comment_num => change.comment.count)
+ FILTER none %]
+ [% ELSIF change.comment.defined && change.fieldname == 'comment_tag' %]
+ [% "Comment $change.comment.count Tagged"
+ FILTER bug_link(operation.bug, comment_num => change.comment.count)
+ FILTER none %]
+ [% ELSE %]
+ [%+ field_descs.${change.fieldname} FILTER html %]
+ [% END %]
+ </td>
+ [% PROCESS change_column change_type = change.removed %]
+ [% PROCESS change_column change_type = change.added %]
+ </tr>
+ [% END %]
+ [% END %]
+ </table>
+ <p>
+ <a href="buglist.cgi?bug_id=[% bug_ids.join(',') FILTER uri %]">
+ Show as a [% terms.Bug %] List</a>
+ </p>
+
+[% ELSE %]
+ <p>
+ No changes.
+ </p>
+[% END %]
+
+[% BLOCK change_column %]
+ <td>
+ [% IF change_type.defined %]
+ [% IF change.fieldname == 'estimated_time' ||
+ change.fieldname == 'remaining_time' ||
+ change.fieldname == 'work_time' %]
+ [% PROCESS formattimeunit time_unit=change_type %]
+ [% ELSIF change.fieldname == 'blocked' ||
+ change.fieldname == 'dependson' %]
+ [% change_type FILTER bug_list_link FILTER none %]
+ [% ELSIF change.fieldname == 'assigned_to' ||
+ change.fieldname == 'reporter' ||
+ change.fieldname == 'qa_contact' ||
+ change.fieldname == 'cc' ||
+ change.fieldname == 'flagtypes.name' %]
+ [% display_value(change.fieldname, change_type) FILTER email FILTER html %]
+ [% ELSE %]
+ [% display_value(change.fieldname, change_type) FILTER html %]
+ [% END %]
+ [% ELSE %]
+ &nbsp;
+ [% END %]
+ </td>
+[% END %]
+[% END %]
+
+[% INCLUDE global/footer.html.tmpl %]
+
+[% BLOCK group_when_link %]
+ <a href="page.cgi?id=user_activity.html&amp;action=run&amp;
+ [%~%]who=[% who FILTER uri %]&amp;
+ [%~%]from=[% from FILTER uri %]&amp;
+ [%~%]to=[% to FILTER uri %]&amp;
+ [%~%]group=when">When</a>
+[% END %]
+
+[% BLOCK group_bug_link %]
+ <a href="page.cgi?id=user_activity.html&amp;action=run&amp;
+ [%~%]who=[% who FILTER uri %]&amp;
+ [%~%]from=[% from FILTER uri %]&amp;
+ [%~%]to=[% to FILTER uri %]&amp;
+ [%~%]group=bug">[% terms.Bug %]</a>
+[% END %]
diff --git a/extensions/BMO/template/en/default/search/search-plugin.xml.tmpl b/extensions/BMO/template/en/default/search/search-plugin.xml.tmpl
new file mode 100644
index 000000000..0c52c1a58
--- /dev/null
+++ b/extensions/BMO/template/en/default/search/search-plugin.xml.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.
+ #%]
+
+[% PROCESS global/variables.none.tmpl %]
+<?xml version="1.0" encoding="UTF-8"?>
+<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
+<ShortName>[% terms.BugzillaTitle %]</ShortName>
+<Description>[% terms.BugzillaTitle %] Quick Search</Description>
+<InputEncoding>UTF-8</InputEncoding>
+<Image height="16" width="16" type="image/vnd.microsoft.icon">https://bugzilla.mozilla.org/extensions/BMO/web/images/favicon.ico</Image>
+<Url type="text/html" method="GET" template="[% urlbase FILTER xml %]buglist.cgi?quicksearch={searchTerms}"/>
+</OpenSearchDescription>
diff --git a/extensions/BMO/web/core.png b/extensions/BMO/web/core.png
new file mode 100644
index 000000000..b9c5053f6
--- /dev/null
+++ b/extensions/BMO/web/core.png
Binary files differ
diff --git a/extensions/BMO/web/images/advanced.png b/extensions/BMO/web/images/advanced.png
new file mode 100644
index 000000000..71a3fcb78
--- /dev/null
+++ b/extensions/BMO/web/images/advanced.png
Binary files differ
diff --git a/extensions/BMO/web/images/background.png b/extensions/BMO/web/images/background.png
new file mode 100644
index 000000000..eb254aab9
--- /dev/null
+++ b/extensions/BMO/web/images/background.png
Binary files differ
diff --git a/extensions/BMO/web/images/bugzilla.png b/extensions/BMO/web/images/bugzilla.png
new file mode 100644
index 000000000..4b7c10284
--- /dev/null
+++ b/extensions/BMO/web/images/bugzilla.png
Binary files differ
diff --git a/extensions/BMO/web/images/creative.png b/extensions/BMO/web/images/creative.png
new file mode 100644
index 000000000..2aeec79ae
--- /dev/null
+++ b/extensions/BMO/web/images/creative.png
Binary files differ
diff --git a/extensions/BMO/web/images/favicon.ico b/extensions/BMO/web/images/favicon.ico
new file mode 100644
index 000000000..c14fec40a
--- /dev/null
+++ b/extensions/BMO/web/images/favicon.ico
Binary files differ
diff --git a/extensions/BMO/web/images/groups/bugzilla-approvers.png b/extensions/BMO/web/images/groups/bugzilla-approvers.png
new file mode 100644
index 000000000..d2414e041
--- /dev/null
+++ b/extensions/BMO/web/images/groups/bugzilla-approvers.png
Binary files differ
diff --git a/extensions/BMO/web/images/groups/calendar-drivers.png b/extensions/BMO/web/images/groups/calendar-drivers.png
new file mode 100644
index 000000000..fc2c1d1e5
--- /dev/null
+++ b/extensions/BMO/web/images/groups/calendar-drivers.png
Binary files differ
diff --git a/extensions/BMO/web/images/guided.png b/extensions/BMO/web/images/guided.png
new file mode 100644
index 000000000..46ba060f8
--- /dev/null
+++ b/extensions/BMO/web/images/guided.png
Binary files differ
diff --git a/extensions/BMO/web/images/mozchomp.gif b/extensions/BMO/web/images/mozchomp.gif
new file mode 100644
index 000000000..ac6549527
--- /dev/null
+++ b/extensions/BMO/web/images/mozchomp.gif
Binary files differ
diff --git a/extensions/BMO/web/images/mozilla-tab.png b/extensions/BMO/web/images/mozilla-tab.png
new file mode 100644
index 000000000..417f6a5c6
--- /dev/null
+++ b/extensions/BMO/web/images/mozilla-tab.png
Binary files differ
diff --git a/extensions/BMO/web/images/notice.png b/extensions/BMO/web/images/notice.png
new file mode 100644
index 000000000..e436c22ae
--- /dev/null
+++ b/extensions/BMO/web/images/notice.png
Binary files differ
diff --git a/extensions/BMO/web/images/presshat.png b/extensions/BMO/web/images/presshat.png
new file mode 100644
index 000000000..a61de59e5
--- /dev/null
+++ b/extensions/BMO/web/images/presshat.png
Binary files differ
diff --git a/extensions/BMO/web/images/sign_warning.png b/extensions/BMO/web/images/sign_warning.png
new file mode 100644
index 000000000..30963f47d
--- /dev/null
+++ b/extensions/BMO/web/images/sign_warning.png
Binary files differ
diff --git a/extensions/BMO/web/images/stop-sign.gif b/extensions/BMO/web/images/stop-sign.gif
new file mode 100644
index 000000000..9b420ec6c
--- /dev/null
+++ b/extensions/BMO/web/images/stop-sign.gif
Binary files differ
diff --git a/extensions/BMO/web/images/throbber.gif b/extensions/BMO/web/images/throbber.gif
new file mode 100644
index 000000000..bc4fa6561
--- /dev/null
+++ b/extensions/BMO/web/images/throbber.gif
Binary files differ
diff --git a/extensions/BMO/web/images/user-engagement.png b/extensions/BMO/web/images/user-engagement.png
new file mode 100644
index 000000000..11fdbc000
--- /dev/null
+++ b/extensions/BMO/web/images/user-engagement.png
Binary files differ
diff --git a/extensions/BMO/web/js/edit_bug.js b/extensions/BMO/web/js/edit_bug.js
new file mode 100644
index 000000000..41a71935e
--- /dev/null
+++ b/extensions/BMO/web/js/edit_bug.js
@@ -0,0 +1,41 @@
+/* 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. */
+
+function init_clone_bug_menu(el, bug_id, product, component) {
+ var diff_url = 'enter_bug.cgi?format=__default__&cloned_bug_id=' + bug_id;
+ var cur_url = diff_url +
+ '&product=' + encodeURIComponent(product) +
+ '&component=' + encodeURIComponent(component);
+ var menu = new YAHOO.widget.Menu('clone_bug_menu', { position : 'dynamic' });
+ menu.addItems([
+ { text: 'Clone to the current product', url: cur_url },
+ { text: 'Clone to a different product', url: diff_url }
+ ]);
+ menu.render(document.body);
+ YAHOO.util.Event.addListener(el, 'click', show_clone_bug_menu, menu);
+}
+
+function show_clone_bug_menu(event, menu) {
+ menu.cfg.setProperty('xy', YAHOO.util.Event.getXY(event));
+ menu.show();
+ event.preventDefault();
+}
+
+// -- make attachment table, comments, new comment textarea equal widths
+
+YAHOO.util.Event.onDOMReady(function() {
+ var comment_tables = Dom.getElementsByClassName('bz_comment_table', 'table', 'comments');
+ if (comment_tables.length) {
+ var comment_width = comment_tables[0].getElementsByTagName('td')[0].clientWidth + 'px';
+ var attachment_table = Dom.get('attachment_table');
+ if (attachment_table)
+ attachment_table.style.width = comment_width;
+ var new_comment = Dom.get('comment');
+ if (new_comment)
+ new_comment.style.width = comment_width;
+ }
+});
diff --git a/extensions/BMO/web/js/edituser_menu.js b/extensions/BMO/web/js/edituser_menu.js
new file mode 100644
index 000000000..383418430
--- /dev/null
+++ b/extensions/BMO/web/js/edituser_menu.js
@@ -0,0 +1,33 @@
+var usermenu_widget;
+
+YAHOO.util.Event.onDOMReady(function() {
+ usermenu_widget = new YAHOO.widget.Menu('usermenu_widget', { position : 'dynamic' });
+ usermenu_widget.addItems([
+ { text: 'Profile', url: '#', target: '_blank' },
+ { text: 'Activity', url: '#', target: '_blank' },
+ { text: 'Mail', url: '#', target: '_blank' },
+ { text: 'Edit', url: '#', target: '_blank' }
+ ]);
+ usermenu_widget.render(document.body);
+});
+
+function show_usermenu(event, id, email, show_edit) {
+ if (!usermenu_widget)
+ return true;
+ if (event.ctrlKey || event.shiftKey || event.altKey || event.metaKey)
+ return true;
+ usermenu_widget.getItem(0).cfg.setProperty('url',
+ 'user_profile?login=' + encodeURIComponent(email));
+ usermenu_widget.getItem(1).cfg.setProperty('url',
+ 'page.cgi?id=user_activity.html&action=run&from=-14d&who=' + encodeURIComponent(email));
+ usermenu_widget.getItem(2).cfg.setProperty('url', 'mailto:' + encodeURIComponent(email));
+ if (show_edit) {
+ usermenu_widget.getItem(3).cfg.setProperty('url', 'editusers.cgi?action=edit&userid=' + id);
+ } else {
+ usermenu_widget.removeItem(3);
+ }
+ usermenu_widget.cfg.setProperty('xy', YAHOO.util.Event.getXY(event));
+ usermenu_widget.show();
+ return false;
+}
+
diff --git a/extensions/BMO/web/js/form_validate.js b/extensions/BMO/web/js/form_validate.js
new file mode 100644
index 000000000..7e9746a5c
--- /dev/null
+++ b/extensions/BMO/web/js/form_validate.js
@@ -0,0 +1,41 @@
+/* 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. */
+
+/**
+ * Form Validation and Interaction
+ **/
+
+//Makes sure that there is an '@' in the address with a '.'
+//somewhere after it (and at least one character in between them)
+function isValidEmail(email) {
+ var at_index = email.indexOf("@");
+ var last_dot = email.lastIndexOf(".");
+ return at_index > 0 && last_dot > (at_index + 1);
+}
+
+//Takes a DOM element id and makes sure that it is filled out
+function isFilledOut(elem_id) {
+ var el = document.getElementById(elem_id);
+ if (!el) {
+ console.error('Failed to find element: ' + elem_id);
+ return false;
+ }
+ var str = el.value;
+ return str.length > 0 && str != "noneselected";
+}
+
+function isChecked(elem_id) {
+ return document.getElementById(elem_id).checked;
+}
+
+function isOneChecked(form_nodelist) {
+ for (var i = 0, il = form_nodelist.length; i < il; i++) {
+ if (form_nodelist[i].checked)
+ return true;
+ }
+ return false;
+}
diff --git a/extensions/BMO/web/js/release_tracking_report.js b/extensions/BMO/web/js/release_tracking_report.js
new file mode 100644
index 000000000..840b57df1
--- /dev/null
+++ b/extensions/BMO/web/js/release_tracking_report.js
@@ -0,0 +1,203 @@
+/* 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. */
+
+var Dom = YAHOO.util.Dom;
+var flagEl;
+var productEl;
+var trackingEl;
+var selectedFields;
+
+// events
+
+function onFieldToggle(cbEl, id) {
+ if (cbEl.checked) {
+ Dom.removeClass('field_' + id + '_td', 'disabled');
+ selectedFields['field_' + id] = id;
+ } else {
+ Dom.addClass('field_' + id + '_td', 'disabled');
+ selectedFields['field_' + id] = false;
+ }
+ Dom.get('field_' + id + '_select').disabled = !cbEl.checked;
+ serialiseForm();
+}
+
+function onProductChange() {
+ var product = productEl.value;
+ var productData = product == '0' ? getFlagByName(flagEl.value) : getProductById(product);
+ var html = '';
+ selectedFields = new Array();
+
+ if (productData) {
+ // update status fields
+ html = '<table>';
+ for(var i = 0, l = productData.fields.length; i < l; i++) {
+ var field = getFieldById(productData.fields[i]);
+ selectedFields['field_' + field.id] = false;
+ html += '<tr>' +
+ '<td>' +
+ '<input type="checkbox" id="field_' + field.id + '_cb" ' +
+ 'onClick="onFieldToggle(this,' + field.id + ')">' +
+ '</td>' +
+ '<td class="disabled" id="field_' + field.id + '_td">' +
+ '<label for="field_' + field.id + '_cb">' +
+ YAHOO.lang.escapeHTML(field.name) + ':</label>' +
+ '</td>' +
+ '<td>' +
+ '<select disabled id="field_' + field.id + '_select">' +
+ '<option value="+">fixed</option>' +
+ '<option value="-">not fixed</option>' +
+ '</select>' +
+ '</td>' +
+ '</tr>';
+ }
+ html += '</table>';
+ }
+ trackingEl.innerHTML = html;
+ serialiseForm();
+}
+
+function onFlagChange() {
+ var flag = flagEl.value;
+ var flagData = getFlagByName(flag);
+ productEl.options.length = 0;
+
+ if (flagData) {
+ // update product select
+ var currentProduct = productEl.value;
+ productEl.options[0] = new Option('(Any Product)', '0');
+ for(var i = 0, l = flagData.products.length; i < l; i++) {
+ var product = getProductById(flagData.products[i]);
+ var n = productEl.length;
+ productEl.options[n] = new Option(product.name, product.id);
+ productEl.options[n].selected = product.id == currentProduct;
+ }
+ }
+ onProductChange();
+}
+
+// form
+
+function selectAllFields() {
+ for(var i = 0, l = fields_data.length; i < l; i++) {
+ var cb = Dom.get('field_' + fields_data[i].id + '_cb');
+ cb.checked = true;
+ onFieldToggle(cb, fields_data[i].id);
+ }
+ serialiseForm();
+}
+
+function selectNoFields() {
+ for(var i = 0, l = fields_data.length; i < l; i++) {
+ var cb = Dom.get('field_' + fields_data[i].id + '_cb');
+ cb.checked = false;
+ onFieldToggle(cb, fields_data[i].id);
+ }
+ serialiseForm();
+}
+
+function invertFields() {
+ for(var i = 0, l = fields_data.length; i < l; i++) {
+ var el = Dom.get('field_' + fields_data[i].id + '_select');
+ if (el.value == '+') {
+ el.options[1].selected = true;
+ } else {
+ el.options[0].selected = true;
+ }
+ }
+ serialiseForm();
+}
+
+function onFormSubmit() {
+ serialiseForm();
+ return true;
+}
+
+function onFormReset() {
+ deserialiseForm('');
+}
+
+function serialiseForm() {
+ var q = flagEl.value + ':' +
+ Dom.get('flag_value').value + ':' +
+ Dom.get('range').value + ':' +
+ productEl.value + ':' +
+ Dom.get('op').value + ':';
+
+ for(var id in selectedFields) {
+ if (selectedFields[id]) {
+ q += selectedFields[id] + Dom.get(id + '_select').value + ':';
+ }
+ }
+
+ Dom.get('q').value = q;
+ Dom.get('bookmark').href = 'page.cgi?id=release_tracking_report.html&q=' +
+ encodeURIComponent(q);
+}
+
+function deserialiseForm(q) {
+ var parts = q.split(/:/);
+ selectValue(flagEl, parts[0]);
+ onFlagChange();
+ selectValue(Dom.get('flag_value'), parts[1]);
+ selectValue(Dom.get('range'), parts[2]);
+ selectValue(productEl, parts[3]);
+ onProductChange();
+ selectValue(Dom.get('op'), parts[4]);
+ for(var i = 5, l = parts.length; i < l; i++) {
+ var part = parts[i];
+ if (part.length) {
+ var value = part.substr(part.length - 1, 1);
+ var id = part.substr(0, part.length - 1);
+ var cb = Dom.get('field_' + id + '_cb');
+ cb.checked = true;
+ onFieldToggle(cb, id);
+ selectValue(Dom.get('field_' + id + '_select'), value);
+ }
+ }
+ serialiseForm();
+}
+
+// utils
+
+YAHOO.util.Event.onDOMReady(function() {
+ flagEl = Dom.get('flag');
+ productEl = Dom.get('product');
+ trackingEl = Dom.get('tracking_span');
+ onFlagChange();
+ deserialiseForm(default_query);
+});
+
+function getFlagByName(name) {
+ for(var i = 0, l = flags_data.length; i < l; i++) {
+ if (flags_data[i].name == name)
+ return flags_data[i];
+ }
+}
+
+function getProductById(id) {
+ for(var i = 0, l = products_data.length; i < l; i++) {
+ if (products_data[i].id == id)
+ return products_data[i];
+ }
+}
+
+function getFieldById(id) {
+ for(var i = 0, l = fields_data.length; i < l; i++) {
+ if (fields_data[i].id == id)
+ return fields_data[i];
+ }
+}
+
+function selectValue(el, value) {
+ for(var i = 0, l = el.options.length; i < l; i++) {
+ if (el.options[i].value == value) {
+ el.options[i].selected = true;
+ return;
+ }
+ }
+ el.options[0].selected = true;
+}
diff --git a/extensions/BMO/web/js/sorttable.js b/extensions/BMO/web/js/sorttable.js
new file mode 100644
index 000000000..0873dc20a
--- /dev/null
+++ b/extensions/BMO/web/js/sorttable.js
@@ -0,0 +1,709 @@
+/*
+ SortTable
+ version 2
+ 7th April 2007
+ Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/
+
+ Instructions:
+ Download this file
+ Add <script src="sorttable.js"></script> to your HTML
+ Add class="sortable" to any table you'd like to make sortable
+ Click on the headers to sort
+
+ Thanks to many, many people for contributions and suggestions.
+ Licenced as X11: http://www.kryogenix.org/code/browser/licence.html
+ This basically means: do what you want with it.
+*/
+
+var stIsIE = /*@cc_on!@*/false;
+
+sorttable = {
+ init: function() {
+ // quit if this function has already been called
+ if (arguments.callee.done) return;
+ // flag this function so we don't do the same thing twice
+ arguments.callee.done = true;
+ // kill the timer
+ if (_timer) clearInterval(_timer);
+
+ if (!document.createElement || !document.getElementsByTagName) return;
+
+ sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
+
+ forEach(document.getElementsByTagName('table'), function(table) {
+ if (table.className.search(/\bsortable\b/) != -1) {
+ sorttable.makeSortable(table);
+ }
+ });
+
+ },
+
+ /*
+ * Prepares the table so that it can be sorted
+ *
+ */
+ makeSortable: function(table) {
+
+ if (table.getElementsByTagName('thead').length == 0) {
+ // table doesn't have a tHead. Since it should have, create one and
+ // put the first table row in it.
+ the = document.createElement('thead');
+ the.appendChild(table.rows[0]);
+ table.insertBefore(the,table.firstChild);
+ }
+ // Safari doesn't support table.tHead, sigh
+ if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0];
+
+ //if (table.tHead.rows.length != 1) return; // can't cope with two header rows
+
+ // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
+ // "total" rows, for example). This is B&R, since what you're supposed
+ // to do is put them in a tfoot. So, if there are sortbottom rows,
+ // for backwards compatibility, move them to tfoot (creating it if needed).
+ sortbottomrows = [];
+ for (var i=0; i<table.rows.length; i++) {
+ if (table.rows[i].className.search(/\bsortbottom\b/) != -1) {
+ sortbottomrows[sortbottomrows.length] = table.rows[i];
+ }
+ }
+
+ if (sortbottomrows) {
+ if (table.tFoot == null) {
+ // table doesn't have a tfoot. Create one.
+ tfo = document.createElement('tfoot');
+ table.appendChild(tfo);
+ }
+ for (var i=0; i<sortbottomrows.length; i++) {
+ tfo.appendChild(sortbottomrows[i]);
+ }
+ delete sortbottomrows;
+ }
+
+ sorttable._walk_through_headers(table);
+ },
+
+ /*
+ * Helper function for preparing the table
+ *
+ */
+ _walk_through_headers: function(table) {
+ // First, gather some information we need to sort the table.
+ var bodies = [];
+ var table_rows = [];
+ var body_size = table.tBodies[0].rows.length;
+
+ // We need to get all the rows
+ for (var i=0; i<table.tBodies.length; i++) {
+ if (!table.tBodies[i].className.match(/\bsorttable_body\b/))
+ continue;
+
+ bodies[bodies.length] = table.tBodies[i];
+ for (j=0; j<table.tBodies[i].rows.length; j++) {
+ table_rows[table_rows.length] = table.tBodies[i].rows[j];
+ }
+ }
+
+ table.sorttable_rows = table_rows;
+ table.sorttable_body_size = body_size;
+ table.sorttable_bodies = bodies;
+
+
+ // work through each column and calculate its type
+
+ // For each row in the header..
+ for (var row_index=0; row_index < table.tHead.rows.length; row_index++) {
+
+ headrow = table.tHead.rows[row_index].cells;
+ // ... Walk through each column and calculate the type.
+ for (var i=0; i<headrow.length; i++) {
+ // Don't sort this column, please
+ if (headrow[i].className.match(/\bsorttable_nosort\b/)) continue;
+
+ // Override sort column index.
+ column_index = i;
+ mtch = headrow[i].className.match(/\bsortable_column_([a-z0-9]+)\b/);
+ if (mtch) column_index = mtch[1];
+
+
+ // Manually override the type with a sorttable_type attribute
+ // Override sort function
+ mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/);
+ if (mtch) override = mtch[1];
+
+ if (mtch && typeof sorttable["sort_"+override] == 'function') {
+ headrow[i].sorttable_sortfunction = sorttable["sort_"+override];
+ } else {
+ headrow[i].sorttable_sortfunction = sorttable.guessType(table, column_index);
+ }
+
+ // make it clickable to sort
+ headrow[i].sorttable_columnindex = column_index;
+ headrow[i].table = table;
+
+ // If the header contains a link, clear the href.
+ for (var k=0; k<headrow[i].childNodes.length; k++) {
+ if (headrow[i].childNodes[k].tagName == 'A') {
+ headrow[i].childNodes[k].href = "javascript:void(0);";
+ }
+ }
+
+ dean_addEvent(headrow[i], "click", sorttable._on_column_header_clicked);
+
+ } // inner for (var i=0; i<headrow.length; i++)
+ } // outer for
+ },
+
+
+
+
+ /*
+ * Helper function for the _on_column_header_clicked handler
+ *
+ */
+
+ _remove_sorted_classes: function(header) {
+ // For each row in the header..
+ for (var j=0; j< header.rows.length; j++) {
+ // ... Walk through each column and calculate the type.
+ row = header.rows[j].cells;
+
+ for (var i=0; i<row.length; i++) {
+ cell = row[i];
+ if (cell.nodeType != 1) return; // an element
+
+ mtch = cell.className.match(/\bsorted_([0-9]+)\b/);
+ if (mtch) {
+ cell.className = cell.className.replace('sorted_'+mtch[1],
+ 'sorted_'+(parseInt(mtch[1])+1));
+ }
+
+ cell.className = cell.className.replace('sorttable_sorted_reverse','');
+ cell.className = cell.className.replace('sorttable_sorted','');
+ }
+ }
+ },
+
+ _check_already_sorted: function(cell) {
+ if (cell.className.search(/\bsorttable_sorted\b/) != -1) {
+ // if we're already sorted by this column, just
+ // reverse the table, which is quicker
+ sorttable.reverse_table(cell);
+
+ sorttable._mark_column_as_sorted(cell, '&#x25BC;', 1);
+ return 1;
+ }
+
+ if (cell.className.search(/\bsorttable_sorted_reverse\b/) != -1) {
+ // if we're already sorted by this column in reverse, just
+ // re-reverse the table, which is quicker
+ sorttable.reverse_table(cell);
+
+ sorttable._mark_column_as_sorted(cell, '&#x25B2;', 0);
+
+ return 1;
+ }
+
+ return 0;
+ },
+
+ /* Visualy mark the cell as sorted.
+ *
+ * @param cell: the cell being marked
+ * @param text: the text being used to mark. you can use html
+ * @param reversed: whether the column is reversed or not.
+ *
+ */
+ _mark_column_as_sorted: function(cell, text, reversed) {
+ // remove eventual class
+ cell.className = cell.className.replace('sorttable_sorted', '');
+ cell.className = cell.className.replace('sorttable_sorted_reverse', '');
+
+ // the column is reversed
+ if (reversed) {
+ cell.className += ' sorttable_sorted_reverse';
+ }
+ else {
+ // remove eventual class
+ cell.className += ' sorttable_sorted';
+ }
+
+ sorttable._remove_sorting_marker();
+
+ marker = document.createElement('span');
+ marker.id = "sorttable_sort_mark";
+ marker.className = "bz_sort_order_primary";
+ marker.innerHTML = text;
+ cell.appendChild(marker);
+ },
+
+ _remove_sorting_marker: function() {
+ mark = document.getElementById('sorttable_sort_mark');
+ if (mark) { mark.parentNode.removeChild(mark); }
+ els = sorttable._getElementsByClassName('bz_sort_order_primary');
+ for(var i=0,j=els.length; i<j; i++) {
+ els[i].parentNode.removeChild(els[i]);
+ }
+ els = sorttable._getElementsByClassName('bz_sort_order_secondary');
+ for(var i=0,j=els.length; i<j; i++) {
+ els[i].parentNode.removeChild(els[i]);
+ }
+ },
+
+ _getElementsByClassName: function(classname, node) {
+ if(!node) node = document.getElementsByTagName("body")[0];
+ var a = [];
+ var re = new RegExp('\\b' + classname + '\\b');
+ var els = node.getElementsByTagName("*");
+ for(var i=0,j=els.length; i<j; i++)
+ if(re.test(els[i].className))a.push(els[i]);
+ return a;
+ },
+
+ /*
+ * This is the callback for when the table header is clicked.
+ *
+ * @param evt: the event that triggered this callback
+ */
+ _on_column_header_clicked: function(evt) {
+
+ // The table is already sorted by this column. Just reverse it.
+ if (sorttable._check_already_sorted(this))
+ return;
+
+
+ // First, remove sorttable_sorted classes from the other header
+ // that is currently sorted and its marker (the simbol indicating
+ // that its sorted.
+ sorttable._remove_sorted_classes(this.table.tHead);
+ mtch = this.className.match(/\bsorted_([0-9]+)\b/);
+ if (mtch) {
+ this.className = this.className.replace('sorted_'+mtch[1], '');
+ }
+ this.className += ' sorted_0 ';
+
+ // This is the text that indicates that the column is sorted.
+ sorttable._mark_column_as_sorted(this, '&#x25BC;', 0);
+
+ sorttable.sort_table(this);
+
+ },
+
+ sort_table: function(cell) {
+ // build an array to sort. This is a Schwartzian transform thing,
+ // i.e., we "decorate" each row with the actual sort key,
+ // sort based on the sort keys, and then put the rows back in order
+ // which is a lot faster because you only do getInnerText once per row
+ col = cell.sorttable_columnindex;
+ rows = cell.table.sorttable_rows;
+
+ var BUGLIST = '';
+
+ for (var j = 0; j < cell.table.sorttable_rows.length; j++) {
+ rows[j].sort_data = sorttable.getInnerText(rows[j].cells[col]);
+ }
+
+ /* If you want a stable sort, uncomment the following line */
+ sorttable.shaker_sort(rows, cell.sorttable_sortfunction);
+ /* and comment out this one */
+ //rows.sort(cell.sorttable_sortfunction);
+
+ // Rebuild the table, using he sorted rows.
+ tb = cell.table.sorttable_bodies[0];
+ body_size = cell.table.sorttable_body_size;
+ body_index = 0;
+
+ for (var j=0; j<rows.length; j++) {
+ if (j % 2)
+ rows[j].className = rows[j].className.replace('bz_row_even',
+ 'bz_row_odd');
+ else
+ rows[j].className = rows[j].className.replace('bz_row_odd',
+ 'bz_row_even');
+
+ tb.appendChild(rows[j]);
+ var bug_id = sorttable.getInnerText(rows[j].cells[0].childNodes[1]);
+ BUGLIST = BUGLIST ? BUGLIST+':'+bug_id : bug_id;
+
+ if (j % body_size == body_size-1) {
+ body_index++;
+ if (body_index < cell.table.sorttable_bodies.length) {
+ tb = cell.table.sorttable_bodies[body_index];
+ }
+ }
+ }
+
+ document.cookie = 'BUGLIST='+BUGLIST;
+
+ cell.table.sorttable_rows = rows;
+ },
+
+ reverse_table: function(cell) {
+ oldrows = cell.table.sorttable_rows;
+ newrows = [];
+
+ for (var i=0; i < oldrows.length; i++) {
+ newrows[newrows.length] = oldrows[i];
+ }
+
+ tb = cell.table.sorttable_bodies[0];
+ body_size = cell.table.sorttable_body_size;
+ body_index = 0;
+
+ var BUGLIST = '';
+
+ cell.table.sorttable_rows = [];
+ for (var i = newrows.length-1; i >= 0; i--) {
+ if (i % 2)
+ newrows[i].className = newrows[i].className.replace('bz_row_even',
+ 'bz_row_odd');
+ else
+ newrows[i].className = newrows[i].className.replace('bz_row_odd',
+ 'bz_row_even');
+
+ tb.appendChild(newrows[i]);
+ cell.table.sorttable_rows.push(newrows[i]);
+
+ var bug_id = sorttable.getInnerText(newrows[i].cells[0].childNodes[1]);
+ BUGLIST = BUGLIST ? BUGLIST+':'+bug_id : bug_id;
+
+ if ((newrows.length-1-i) % body_size == body_size-1) {
+ body_index++;
+ if (body_index < cell.table.sorttable_bodies.length) {
+ tb = cell.table.sorttable_bodies[body_index];
+ }
+ }
+
+ }
+
+ document.cookie = 'BUGLIST='+BUGLIST;
+
+ delete newrows;
+ },
+
+ guessType: function(table, column) {
+ // guess the type of a column based on its first non-blank row
+ sortfn = sorttable.sort_alpha;
+ for (var i=0; i<table.sorttable_bodies[0].rows.length; i++) {
+ text = sorttable.getInnerText(table.sorttable_bodies[0].rows[i].cells[column]);
+ if (text != '') {
+ if (text.match(/^-?[£$¤]?[\d,.]+%?$/)) {
+ return sorttable.sort_numeric;
+ }
+ // check for a date: dd/mm/yyyy or dd/mm/yy
+ // can have / or . or - as separator
+ // can be mm/dd as well
+ possdate = text.match(sorttable.DATE_RE)
+ if (possdate) {
+ // looks like a date
+ first = parseInt(possdate[1]);
+ second = parseInt(possdate[2]);
+ if (first > 12) {
+ // definitely dd/mm
+ return sorttable.sort_ddmm;
+ } else if (second > 12) {
+ return sorttable.sort_mmdd;
+ } else {
+ // looks like a date, but we can't tell which, so assume
+ // that it's dd/mm (English imperialism!) and keep looking
+ sortfn = sorttable.sort_ddmm;
+ }
+ }
+ }
+ }
+ return sortfn;
+ },
+
+ getInnerText: function(node) {
+ // gets the text we want to use for sorting for a cell.
+ // strips leading and trailing whitespace.
+ // this is *not* a generic getInnerText function; it's special to sorttable.
+ // for example, you can override the cell text with a customkey attribute.
+ // it also gets .value for <input> fields.
+
+ hasInputs = (typeof node.getElementsByTagName == 'function') &&
+ node.getElementsByTagName('input').length;
+
+ if (typeof node.getAttribute != 'undefined' && node.getAttribute("sorttable_customkey") != null) {
+ return node.getAttribute("sorttable_customkey");
+ }
+ else if (typeof node.textContent != 'undefined' && !hasInputs) {
+ return node.textContent.replace(/^\s+|\s+$/g, '');
+ }
+ else if (typeof node.innerText != 'undefined' && !hasInputs) {
+ return node.innerText.replace(/^\s+|\s+$/g, '');
+ }
+ else if (typeof node.text != 'undefined' && !hasInputs) {
+ return node.text.replace(/^\s+|\s+$/g, '');
+ }
+ else {
+ switch (node.nodeType) {
+ case 3:
+ if (node.nodeName.toLowerCase() == 'input') {
+ return node.value.replace(/^\s+|\s+$/g, '');
+ }
+ case 4:
+ return node.nodeValue.replace(/^\s+|\s+$/g, '');
+ break;
+ case 1:
+ case 11:
+ var innerText = '';
+ for (var i = 0; i < node.childNodes.length; i++) {
+ innerText += sorttable.getInnerText(node.childNodes[i]);
+ }
+ return innerText.replace(/^\s+|\s+$/g, '');
+ break;
+ default:
+ return '';
+ }
+ }
+ },
+
+ /* sort functions
+ each sort function takes two parameters, a and b
+ you are comparing a.sort_data and b.sort_data */
+ sort_numeric: function(a,b) {
+ aa = parseFloat(a.sort_data.replace(/[^0-9.-]/g,''));
+ if (isNaN(aa)) aa = 0;
+ bb = parseFloat(b.sort_data.replace(/[^0-9.-]/g,''));
+ if (isNaN(bb)) bb = 0;
+ return aa-bb;
+ },
+
+ sort_alpha: function(a,b) {
+ if (a.sort_data.toLowerCase()==b.sort_data.toLowerCase()) return 0;
+ if (a.sort_data.toLowerCase()<b.sort_data.toLowerCase()) return -1;
+ return 1;
+ },
+
+ sort_ddmm: function(a,b) {
+ mtch = a.sort_data.match(sorttable.DATE_RE);
+ y = mtch[3]; m = mtch[2]; d = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt1 = y+m+d;
+ mtch = b.sort_data.match(sorttable.DATE_RE);
+ y = mtch[3]; m = mtch[2]; d = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt2 = y+m+d;
+ if (dt1==dt2) return 0;
+ if (dt1<dt2) return -1;
+ return 1;
+ },
+
+ sort_mmdd: function(a,b) {
+ mtch = a.sort_data.match(sorttable.DATE_RE);
+ y = mtch[3]; d = mtch[2]; m = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt1 = y+m+d;
+ mtch = b.sort_data.match(sorttable.DATE_RE);
+ y = mtch[3]; d = mtch[2]; m = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt2 = y+m+d;
+ if (dt1==dt2) return 0;
+ if (dt1<dt2) return -1;
+ return 1;
+ },
+
+ shaker_sort: function(list, comp_func) {
+ // A stable sort function to allow multi-level sorting of data
+ // see: http://en.wikipedia.org/wiki/Cocktail_sort
+ // thanks to Joseph Nahmias
+ var b = 0;
+ var t = list.length - 1;
+ var swap = true;
+
+ while(swap) {
+ swap = false;
+ for(var i = b; i < t; ++i) {
+ if ( comp_func(list[i], list[i+1]) > 0 ) {
+ var q = list[i]; list[i] = list[i+1]; list[i+1] = q;
+ swap = true;
+ }
+ } // for
+ t--;
+
+ if (!swap) break;
+
+ for(var i = t; i > b; --i) {
+ if ( comp_func(list[i], list[i-1]) < 0 ) {
+ var q = list[i]; list[i] = list[i-1]; list[i-1] = q;
+ swap = true;
+ }
+ } // for
+ b++;
+
+ } // while(swap)
+ }
+}
+
+/* ******************************************************************
+ Supporting functions: bundled here to avoid depending on a library
+ ****************************************************************** */
+
+// Dean Edwards/Matthias Miller/John Resig
+
+/* for Mozilla/Opera9 */
+if (document.addEventListener) {
+ document.addEventListener("DOMContentLoaded", sorttable.init, false);
+}
+
+/* for Internet Explorer */
+/*@cc_on @*/
+/*@if (@_win32)
+ // IE doesn't have a way to test if the DOM is loaded
+ // doing a deferred script load with onReadyStateChange checks is
+ // problematic, so poll the document until it is scrollable
+ // http://blogs.atlassian.com/developer/2008/03/when_ie_says_dom_is_ready_but.html
+ var loadTestTimer = function() {
+ try {
+ if (document.readyState != "loaded" && document.readyState != "complete") {
+ document.documentElement.doScroll("left");
+ }
+ sorttable.init(); // call the onload handler
+ } catch(error) {
+ setTimeout(loadTestTimer, 100);
+ }
+ };
+ loadTestTimer();
+/*@end @*/
+
+/* for Safari */
+if (/WebKit/i.test(navigator.userAgent)) { // sniff
+ var _timer = setInterval(function() {
+ if (/loaded|complete/.test(document.readyState)) {
+ sorttable.init(); // call the onload handler
+ }
+ }, 10);
+}
+
+/* for other browsers */
+window.onload = sorttable.init;
+
+// written by Dean Edwards, 2005
+// with input from Tino Zijdel, Matthias Miller, Diego Perini
+
+// http://dean.edwards.name/weblog/2005/10/add-event/
+
+function dean_addEvent(element, type, handler) {
+ if (element.addEventListener) {
+ element.addEventListener(type, handler, false);
+ } else {
+ // assign each event handler a unique ID
+ if (!handler.$$guid) handler.$$guid = dean_addEvent.guid++;
+ // create a hash table of event types for the element
+ if (!element.events) element.events = {};
+ // create a hash table of event handlers for each element/event pair
+ var handlers = element.events[type];
+ if (!handlers) {
+ handlers = element.events[type] = {};
+ // store the existing event handler (if there is one)
+ if (element["on" + type]) {
+ handlers[0] = element["on" + type];
+ }
+ }
+ // store the event handler in the hash table
+ handlers[handler.$$guid] = handler;
+ // assign a global event handler to do all the work
+ element["on" + type] = handleEvent;
+ }
+};
+// a counter used to create unique IDs
+dean_addEvent.guid = 1;
+
+function removeEvent(element, type, handler) {
+ if (element.removeEventListener) {
+ element.removeEventListener(type, handler, false);
+ } else {
+ // delete the event handler from the hash table
+ if (element.events && element.events[type]) {
+ delete element.events[type][handler.$$guid];
+ }
+ }
+};
+
+function handleEvent(event) {
+ var returnValue = true;
+ // grab the event object (IE uses a global event object)
+ event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
+ // get a reference to the hash table of event handlers
+ var handlers = this.events[event.type];
+ // execute each event handler
+ for (var i in handlers) {
+ this.$$handleEvent = handlers[i];
+ if (this.$$handleEvent(event) === false) {
+ returnValue = false;
+ }
+ }
+ return returnValue;
+};
+
+function fixEvent(event) {
+ // add W3C standard event methods
+ event.preventDefault = fixEvent.preventDefault;
+ event.stopPropagation = fixEvent.stopPropagation;
+ return event;
+};
+fixEvent.preventDefault = function() {
+ this.returnValue = false;
+};
+fixEvent.stopPropagation = function() {
+ this.cancelBubble = true;
+}
+
+// Dean's forEach: http://dean.edwards.name/base/forEach.js
+/*
+ forEach, version 1.0
+ Copyright 2006, Dean Edwards
+ License: http://www.opensource.org/licenses/mit-license.php
+*/
+
+// array-like enumeration
+if (!Array.forEach) { // mozilla already supports this
+ Array.forEach = function(array, block, context) {
+ for (var i = 0; i < array.length; i++) {
+ block.call(context, array[i], i, array);
+ }
+ };
+}
+
+// generic enumeration
+Function.prototype.forEach = function(object, block, context) {
+ for (var key in object) {
+ if (typeof this.prototype[key] == "undefined") {
+ block.call(context, object[key], key, object);
+ }
+ }
+};
+
+// character enumeration
+String.forEach = function(string, block, context) {
+ Array.forEach(string.split(""), function(chr, index) {
+ block.call(context, chr, index, string);
+ });
+};
+
+// globally resolve forEach enumeration
+var forEach = function(object, block, context) {
+ if (object) {
+ var resolve = Object; // default
+ if (object instanceof Function) {
+ // functions have a "length" property
+ resolve = Function;
+ } else if (object.forEach instanceof Function) {
+ // the object implements a custom forEach method so use that
+ object.forEach(block, context);
+ return;
+ } else if (typeof object == "string") {
+ // the object is a string
+ resolve = String;
+ } else if (typeof object.length == "number") {
+ // the object is array-like
+ resolve = Array;
+ }
+ resolve.forEach(object, block, context);
+ }
+};
+
diff --git a/extensions/BMO/web/js/swag.js b/extensions/BMO/web/js/swag.js
new file mode 100644
index 000000000..cd9561b54
--- /dev/null
+++ b/extensions/BMO/web/js/swag.js
@@ -0,0 +1,60 @@
+/**
+ * Swag Request Form Functions
+ * Form Interal Swag Request Form
+ * dtran
+ * 7/6/09
+ **/
+
+
+function evalToNumber(numberString) {
+ if(numberString=='') return 0;
+ return parseInt(numberString);
+}
+
+function evalToNumberString(numberString) {
+ if(numberString=='') return '0';
+ return numberString;
+}
+//item_array should be an array of DOM element ids
+function getTotal(item_array) {
+ var total = 0;
+ for(var i in item_array) {
+ total += evalToNumber(document.getElementById(item_array[i]).value);
+ }
+ return total;
+}
+
+function calculateTotalSwag() {
+ document.getElementById('Totalswag').value =
+ getTotal( new Array('Lanyards',
+ 'Stickers',
+ 'Bracelets',
+ 'Tattoos',
+ 'Buttons',
+ 'Posters'));
+
+}
+
+
+function calculateTotalMensShirts() {
+ document.getElementById('mens_total').value =
+ getTotal( new Array('mens_s',
+ 'mens_m',
+ 'mens_l',
+ 'mens_xl',
+ 'mens_xxl',
+ 'mens_xxxl'));
+
+}
+
+
+function calculateTotalWomensShirts() {
+ document.getElementById('womens_total').value =
+ getTotal( new Array('womens_s',
+ 'womens_m',
+ 'womens_l',
+ 'womens_xl',
+ 'womens_xxl',
+ 'womens_xxxl'));
+
+}
diff --git a/extensions/BMO/web/js/triage_reports.js b/extensions/BMO/web/js/triage_reports.js
new file mode 100644
index 000000000..855b577d7
--- /dev/null
+++ b/extensions/BMO/web/js/triage_reports.js
@@ -0,0 +1,83 @@
+var Dom = YAHOO.util.Dom;
+
+function onSelectProduct() {
+ var component = Dom.get('component');
+ if (Dom.get('product').value == '') {
+ bz_clearOptions(component);
+ return;
+ }
+ selectProduct(Dom.get('product'), component);
+ // selectProduct only supports __Any__ on both elements
+ // we only want it on component, so add it back in
+ try {
+ component.add(new Option('__Any__', ''), component.options[0]);
+ } catch(e) {
+ // support IE
+ component.add(new Option('__Any__', ''), 0);
+ }
+ component.value = '';
+}
+
+function onCommenterChange() {
+ var commenter_is = Dom.get('commenter_is');
+ if (Dom.get('commenter').value == 'is') {
+ Dom.removeClass(commenter_is, 'hidden');
+ } else {
+ Dom.addClass(commenter_is, 'hidden');
+ }
+}
+
+function onLastChange() {
+ var last_is_span = Dom.get('last_is_span');
+ if (Dom.get('last').value == 'is') {
+ Dom.removeClass(last_is_span, 'hidden');
+ } else {
+ Dom.addClass(last_is_span, 'hidden');
+ }
+}
+
+function onGenerateReport() {
+ if (Dom.get('product').value == '') {
+ alert('You must select a product.');
+ return false;
+ }
+ if (Dom.get('component').value == '' && !Dom.get('component').options[0].selected) {
+ alert('You must select at least one component.');
+ return false;
+ }
+ if (!(Dom.get('filter_commenter').checked || Dom.get('filter_last').checked)) {
+ alert('You must select at least one comment filter.');
+ return false;
+ }
+ if (Dom.get('filter_commenter').checked
+ && Dom.get('commenter').value == 'is'
+ && Dom.get('commenter_is').value == '')
+ {
+ alert('You must specify the last commenter\'s email address.');
+ return false;
+ }
+ if (Dom.get('filter_last').checked
+ && Dom.get('last').value == 'is'
+ && Dom.get('last_is').value == '')
+ {
+ alert('You must specify the "comment is older than" date.');
+ return false;
+ }
+ return true;
+}
+
+YAHOO.util.Event.onDOMReady(function() {
+ onSelectProduct();
+ onCommenterChange();
+ onLastChange();
+
+ var component = Dom.get('component');
+ if (selected_components.length == 0)
+ return;
+ component.options[0].selected = false;
+ for (var i = 0, n = selected_components.length; i < n; i++) {
+ var index = bz_optionIndex(component, selected_components[i]);
+ if (index != -1)
+ component.options[index].selected = true;
+ }
+});
diff --git a/extensions/BMO/web/js/webtrends.js b/extensions/BMO/web/js/webtrends.js
new file mode 100644
index 000000000..fd0aca29e
--- /dev/null
+++ b/extensions/BMO/web/js/webtrends.js
@@ -0,0 +1,213 @@
+function WebTrends(options){var that=this;this.dcsid="dcsis0ifv10000gg3ag82u4rf_7b1e";this.rate=100;this.fpcdom=".mozilla.org";this.trackevents=false;if(typeof(options)!="undefined")
+{if(typeof(options.dcsid)!="undefined")this.dcsid=options.dcsid;if(typeof(options.rate)!="undefined")this.rate=options.rate;if(typeof(options.fpcdom)!="undefined")this.fpcdom=options.fpcdom;if(typeof(this.fpcdom)!="undefined"&&this.fpcdom.substring(0,1)!='.')this.fpcdom='.'+this.fpcdom;if(typeof(options.trackevents)!="undefined")this.trackevents=options.trackevents;}
+this.domain="statse.webtrendslive.com";this.timezone=0;this.onsitedoms="";this.downloadtypes="xls,doc,pdf,txt,csv,zip,dmg,exe";this.navigationtag="div,table";this.enabled=true;this.i18n=false;this.fpc="WT_FPC";this.paidsearchparams="gclid";this.splitvalue="";this.preserve=true;this.DCSdir={};this.DCS={};this.WT={};this.DCSext={};this.images=[];this.index=0;this.exre=(function()
+{return(window.RegExp?new RegExp("dcs(uri)|(ref)|(aut)|(met)|(sta)|(sip)|(pro)|(byt)|(dat)|(p3p)|(cfg)|(redirect)|(cip)","i"):"");})();this.re=(function()
+{return(window.RegExp?(that.i18n?{"%25":/\%/g,"%26":/\&/g}:{"%09":/\t/g,"%20":/ /g,"%23":/\#/g,"%26":/\&/g,"%2B":/\+/g,"%3F":/\?/g,"%5C":/\\/g,"%22":/\"/g,"%7F":/\x7F/g,"%A0":/\xA0/g}):"");})();}
+WebTrends.prototype.dcsGetId=function(){if(this.enabled&&(document.cookie.indexOf(this.fpc+"=")==-1)&&(document.cookie.indexOf("WTLOPTOUT=")==-1)){document.write("<scr"+"ipt type='text/javascript' src='"+"http"+(window.location.protocol.indexOf('https:')==0?'s':'')+"://"+this.domain+"/"+this.dcsid+"/wtid.js"+"'><\/scr"+"ipt>");}}
+WebTrends.prototype.dcsGetCookie=function(name)
+{var cookies=document.cookie.split("; ");var cmatch=[];var idx=0;var i=0;var namelen=name.length;var clen=cookies.length;for(i=0;i<clen;i++)
+{var c=cookies[i];if((c.substring(0,namelen+1))==(name+"=")){cmatch[idx++]=c;}}
+var cmatchCount=cmatch.length;if(cmatchCount>0)
+{idx=0;if((cmatchCount>1)&&(name==this.fpc))
+{var dLatest=new Date(0);for(i=0;i<cmatchCount;i++)
+{var lv=parseInt(this.dcsGetCrumb(cmatch[i],"lv"));var dLst=new Date(lv);if(dLst>dLatest)
+{dLatest.setTime(dLst.getTime());idx=i;}}}
+return unescape(cmatch[idx].substring(namelen+1));}
+else
+{return null;}}
+WebTrends.prototype.dcsGetCrumb=function(cval,crumb,sep){var aCookie=cval.split(sep||":");for(var i=0;i<aCookie.length;i++){var aCrumb=aCookie[i].split("=");if(crumb==aCrumb[0]){return aCrumb[1];}}
+return null;}
+WebTrends.prototype.dcsGetIdCrumb=function(cval,crumb){var id=cval.substring(0,cval.indexOf(":lv="));var aCrumb=id.split("=");for(var i=0;i<aCrumb.length;i++){if(crumb==aCrumb[0]){return aCrumb[1];}}
+return null;}
+WebTrends.prototype.dcsIsFpcSet=function(name,id,lv,ss){var c=this.dcsGetCookie(name);if(c){return((id==this.dcsGetIdCrumb(c,"id"))&&(lv==this.dcsGetCrumb(c,"lv"))&&(ss==this.dcsGetCrumb(c,"ss")))?0:3;}
+return 2;}
+WebTrends.prototype.dcsFPC=function(){if(document.cookie.indexOf("WTLOPTOUT=")!=-1){return;}
+var WT=this.WT;var name=this.fpc;var dCur=new Date();var adj=(dCur.getTimezoneOffset()*60000)+(this.timezone*3600000);dCur.setTime(dCur.getTime()+adj);var dExp=new Date(dCur.getTime()+315360000000);var dSes=new Date(dCur.getTime());WT.co_f=WT.vtid=WT.vtvs=WT.vt_f=WT.vt_f_a=WT.vt_f_s=WT.vt_f_d=WT.vt_f_tlh=WT.vt_f_tlv="";if(document.cookie.indexOf(name+"=")==-1){if((typeof(gWtId)!="undefined")&&(gWtId!="")){WT.co_f=gWtId;}
+else if((typeof(gTempWtId)!="undefined")&&(gTempWtId!="")){WT.co_f=gTempWtId;WT.vt_f="1";}
+else{WT.co_f="2";var curt=dCur.getTime().toString();for(var i=2;i<=(32-curt.length);i++){WT.co_f+=Math.floor(Math.random()*16.0).toString(16);}
+WT.co_f+=curt;WT.vt_f="1";}
+if(typeof(gWtAccountRollup)=="undefined"){WT.vt_f_a="1";}
+WT.vt_f_s=WT.vt_f_d="1";WT.vt_f_tlh=WT.vt_f_tlv="0";}
+else{var c=this.dcsGetCookie(name);var id=this.dcsGetIdCrumb(c,"id");var lv=parseInt(this.dcsGetCrumb(c,"lv"));var ss=parseInt(this.dcsGetCrumb(c,"ss"));if((id==null)||(id=="null")||isNaN(lv)||isNaN(ss)){return;}
+WT.co_f=id;var dLst=new Date(lv);WT.vt_f_tlh=Math.floor((dLst.getTime()-adj)/1000);dSes.setTime(ss);if((dCur.getTime()>(dLst.getTime()+1800000))||(dCur.getTime()>(dSes.getTime()+28800000))){WT.vt_f_tlv=Math.floor((dSes.getTime()-adj)/1000);dSes.setTime(dCur.getTime());WT.vt_f_s="1";}
+if((dCur.getDay()!=dLst.getDay())||(dCur.getMonth()!=dLst.getMonth())||(dCur.getYear()!=dLst.getYear())){WT.vt_f_d="1";}}
+WT.co_f=escape(WT.co_f);WT.vtid=(typeof(this.vtid)=="undefined")?WT.co_f:(this.vtid||"");WT.vtvs=(dSes.getTime()-adj).toString();var expiry="; expires="+dExp.toGMTString();var cur=dCur.getTime().toString();var ses=dSes.getTime().toString();document.cookie=name+"="+"id="+WT.co_f+":lv="+cur+":ss="+ses+expiry+"; path=/"+(((this.fpcdom!=""))?("; domain="+this.fpcdom):(""));var rc=this.dcsIsFpcSet(name,WT.co_f,cur,ses);if(rc!=0){WT.co_f=WT.vtvs=WT.vt_f_s=WT.vt_f_d=WT.vt_f_tlh=WT.vt_f_tlv="";if(typeof(this.vtid)=="undefined"){WT.vtid="";}
+WT.vt_f=WT.vt_f_a=rc;}}
+WebTrends.prototype.dcsIsOnsite=function(host){if(host.length>0){host=host.toLowerCase();if(host==window.location.hostname.toLowerCase()){return true;}
+if(typeof(this.onsitedoms.test)=="function"){return this.onsitedoms.test(host);}
+else if(this.onsitedoms.length>0){var doms=this.dcsSplit(this.onsitedoms);var len=doms.length;for(var i=0;i<len;i++){if(host==doms[i]){return true;}}}}
+return false;}
+WebTrends.prototype.dcsTypeMatch=function(pth,typelist){var type=pth.toLowerCase().substring(pth.lastIndexOf(".")+1,pth.length);var types=this.dcsSplit(typelist);var tlen=types.length;for(var i=0;i<tlen;i++){if(type==types[i]){return true;}}
+return false;}
+WebTrends.prototype.dcsEvt=function(evt,tag){var e=evt.target||evt.srcElement;while(e.tagName&&(e.tagName.toLowerCase()!=tag.toLowerCase())){e=e.parentElement||e.parentNode;}
+return e;}
+WebTrends.prototype.dcsNavigation=function(evt){var id="";var cname="";var elems=this.dcsSplit(this.navigationtag);var elen=elems.length;var i,e,elem;for(i=0;i<elen;i++)
+{elem=elems[i];if(elem.length)
+{e=this.dcsEvt(evt,elem);id=(e.getAttribute&&e.getAttribute("id"))?e.getAttribute("id"):"";cname=e.className||"";if(id.length||cname.length){break;}}}
+return id.length?id:cname;}
+WebTrends.prototype.dcsBind=function(event,func){if((typeof(func)=="function")&&document.body){if(document.body.addEventListener){document.body.addEventListener(event,func.wtbind(this),true);}
+else if(document.body.attachEvent){document.body.attachEvent("on"+event,func.wtbind(this));}}}
+WebTrends.prototype.dcsET=function(){var e=(navigator.appVersion.indexOf("MSIE")!=-1)?"click":"mousedown";this.dcsBind(e,this.dcsDownload);this.dcsBind("contextmenu",this.dcsRightClick);this.dcsBind(e,this.dcsLinkTrack);}
+WebTrends.prototype.dcsMultiTrack=function(){var args=dcsMultiTrack.arguments?dcsMultiTrack.arguments:arguments;if(args.length%2==0){this.dcsSaveProps(args);this.dcsSetProps(args);var dCurrent=new Date();this.DCS.dcsdat=dCurrent.getTime();this.dcsFPC();this.dcsTag();this.dcsRestoreProps();}}
+WebTrends.prototype.dcsLinkTrack=function(evt)
+{evt=evt||(window.event||"");if(evt&&((typeof(evt.which)!="number")||(evt.which==1)))
+{var e=this.dcsEvt(evt,"A");var f=this.dcsEvt(evt,"IMG");if(e.href&&e.protocol&&e.protocol.indexOf("http")!=-1&&!this.dcsLinkTrackException(e))
+{if((navigator.appVersion.indexOf("MSIE")==-1)&&((e.onclick)||(e.onmousedown)))
+{this.dcsSetVarCap(e);}
+var hn=e.hostname?(e.hostname.split(":")[0]):"";var qry=e.search?e.search.substring(e.search.indexOf("?")+1,e.search.length):"";var pth=e.pathname?((e.pathname.indexOf("/")!=0)?"/"+e.pathname:e.pathname):"/";var ti='';if(f.alt)
+{ti=f.alt;}
+else
+{if(document.all)
+{ti=e.title||e.innerText||e.innerHTML||"";}
+else
+{ti=e.title||e.text||e.innerHTML||"";}}
+hn=this.DCS.setvar_dcssip||hn;pth=this.DCS.setvar_dcsuri||pth;qry=this.DCS.setvar_dcsqry||qry;ti=this.WT.setvar_ti||ti;ti=this.dcsTrim(ti);this.WT.mc_id=this.WT.setvar_mc_id||"";this.WT.sp=this.WT.ad=this.DCS.setvar_dcsuri=this.DCS.setvar_dcssip=this.DCS.setvar_dcsqry=this.WT.setvar_ti=this.WT.setvar_mc_id="";this.dcsMultiTrack("DCS.dcssip",hn,"DCS.dcsuri",pth,"DCS.dcsqry",this.trimoffsiteparams?"":qry,"DCS.dcsref",window.location,"WT.ti","Link:"+ti,"WT.dl","1","WT.nv",this.dcsNavigation(evt),"WT.sp","","WT.ad","","WT.AutoLinkTrack","1");this.DCS.dcssip=this.DCS.dcsuri=this.DCS.dcsqry=this.DCS.dcsref=this.WT.ti=this.WT.dl=this.WT.nv="";}}}
+WebTrends.prototype.dcsTrim=function(sString)
+{while(sString.substring(0,1)==' ')
+{sString=sString.substring(1,sString.length);}
+while(sString.substring(sString.length-1,sString.length)==' ')
+{sString=sString.substring(0,sString.length-1);}
+return sString;}
+WebTrends.prototype.dcsSetVarCap=function(e)
+{if(e.onclick)
+var gCap=e.onclick.toString();else if(e.onmousedown)
+var gCap=e.onmousedown.toString();var gStart=gCap.substring(gCap.indexOf("dcsSetVar(")+10,gCap.length)||gCap.substring(gCap.indexOf("_tag.dcsSetVar(")+16,gCap.length);var gEnd=gStart.substring(0,gStart.indexOf(");")).replace(/\s"/gi,"").replace(/"/gi,"");var gSplit=gEnd.split(",");if(gSplit.length!=-1)
+{for(var i=0;i<gSplit.length;i+=2)
+{if(gSplit[i].indexOf('WT.')==0)
+{if(this.dcsSetVarValidate(gSplit[i]))
+{this.WT["setvar_"+gSplit[i].substring(3)]=gSplit[i+1];}
+else
+{this.WT[gSplit[i].substring(3)]=gSplit[i+1];}}
+else if(gSplit[i].indexOf('DCS.')==0)
+{if(this.dcsSetVarValidate(gSplit[i]))
+{this.DCS["setvar_"+gSplit[i].substring(4)]=gSplit[i+1];}
+else
+{this.DCS[gSplit[i].substring(4)]=gSplit[i+1];}}
+else if(gSplit[i].indexOf('DCSext.')==0)
+{if(this.dcsSetVarValidate(gSplit[i]))
+{this.DCSext["setvar_"+gSplit[i].substring(7)]=gSplit[i+1];}
+else
+{this.DCSext[gSplit[i].substring(7)]=gSplit[i+1];}}
+else if(gSplit[i].indexOf('DCSdir.')==0)
+{if(this.dcsSetVarValidate(gSplit[i]))
+{this.DCSdir["setvar_"+gSplit[i].substring(7)]=gSplit[i+1];}
+else
+{this.DCSdir[gSplit[i].substring(7)]=gSplit[i+1];}}}}}
+WebTrends.prototype.dcsSetVarValidate=function(validate)
+{var wtParamList="DCS.dcssip,DCS.dcsuri,DCS.dcsqry,WT.ti,WT.mc_id".split(",");for(var i=0;i<wtParamList.length;i++)
+{if(wtParamList[i]==validate)
+{return 1;}}
+return 0;}
+WebTrends.prototype.dcsSetVar=function()
+{var args=dcsSetVar.arguments?dcsSetVar.arguments:arguments;if((args.length%2==0)&&(navigator.appVersion.indexOf("MSIE")!=-1)){for(var i=0;i<args.length;i+=2){if(args[i].indexOf('WT.')==0){if(this.dcsSetVarValidate(args[i])){this.WT["setvar_"+args[i].substring(3)]=args[i+1];}
+else{this.WT[args[i].substring(3)]=args[i+1];}}
+else if(args[i].indexOf('DCS.')==0){if(this.dcsSetVarValidate(args[i])){this.DCS["setvar_"+args[i].substring(4)]=args[i+1];}
+else{this.DCS[args[i].substring(4)]=args[i+1];}}
+else if(args[i].indexOf('DCSext.')==0){if(this.dcsSetVarValidate(args[i])){this.DCSext["setvar_"+args[i].substring(7)]=args[i+1];}
+else{this.DCSext[args[i].substring(7)]=args[i+1];}}
+else if(args[i].indexOf('DCSdir.')==0){if(this.dcsSetVarValidate(args[i])){this.DCSdir["setvar_"+args[i].substring(7)]=args[i+1];}
+else{this.DCSdir[args[i].substring(7)]=args[i+1];}}}}}
+WebTrends.prototype.dcsLinkTrackException=function(n)
+{try
+{var b=0;if(this.DCSdir.gTrackExceptions)
+{var e=this.DCSdir.gTrackExceptions.split(",");while(b!=1)
+{if(n.tagName&&n.tagName=="body")
+{b=1;return false}
+else
+{if(n.className)
+{var f=String(n.className).split(" ");for(var c=0;c<e.length;c++)for(var d=0;d<f.length;d++)
+{if(f[d]==e[c])
+{b=1;return true}}}}
+n=n.parentNode}}
+else
+{return false;}}
+catch(g){}}
+WebTrends.prototype.dcsCleanUp=function(){this.DCS={};this.WT={};this.DCSext={};if(arguments.length%2==0){this.dcsSetProps(arguments);}}
+WebTrends.prototype.dcsSetProps=function(args){for(var i=0;i<args.length;i+=2){if(args[i].indexOf('WT.')==0){this.WT[args[i].substring(3)]=args[i+1];}
+else if(args[i].indexOf('DCS.')==0){this.DCS[args[i].substring(4)]=args[i+1];}
+else if(args[i].indexOf('DCSext.')==0){this.DCSext[args[i].substring(7)]=args[i+1];}}}
+WebTrends.prototype.dcsSaveProps=function(args){var i,key,param;if(this.preserve){this.args=[];for(i=0;i<args.length;i+=2){param=args[i];if(param.indexOf('WT.')==0){key=param.substring(3);this.args[i]=param;this.args[i+1]=this.WT[key]||"";}
+else if(param.indexOf('DCS.')==0){key=param.substring(4);this.args[i]=param;this.args[i+1]=this.DCS[key]||"";}
+else if(param.indexOf('DCSext.')==0){key=param.substring(7);this.args[i]=param;this.args[i+1]=this.DCSext[key]||"";}}}}
+WebTrends.prototype.dcsRestoreProps=function(){if(this.preserve){this.dcsSetProps(this.args);this.args=[];}}
+WebTrends.prototype.dcsSplit=function(list){var items=list.toLowerCase().split(",");var len=items.length;for(var i=0;i<len;i++){items[i]=items[i].replace(/^\s*/,"").replace(/\s*$/,"");}
+return items;}
+WebTrends.prototype.dcsDownload=function(evt){evt=evt||(window.event||"");if(evt&&((typeof(evt.which)!="number")||(evt.which==1))){var e=this.dcsEvt(evt,"A");if(e.href){var hn=e.hostname?(e.hostname.split(":")[0]):"";if(this.dcsIsOnsite(hn)&&this.dcsTypeMatch(e.pathname,this.downloadtypes)){var qry=e.search?e.search.substring(e.search.indexOf("?")+1,e.search.length):"";var pth=e.pathname?((e.pathname.indexOf("/")!=0)?"/"+e.pathname:e.pathname):"/";var ttl="";var text=document.all?e.innerText:e.text;var img=this.dcsEvt(evt,"IMG");if(img.alt){ttl=img.alt;}
+else if(text){ttl=text;}
+else if(e.innerHTML){ttl=e.innerHTML;}
+this.dcsMultiTrack("DCS.dcssip",hn,"DCS.dcsuri",pth,"DCS.dcsqry",e.search||"","WT.ti","Download:"+ttl,"WT.dl","20","WT.nv",this.dcsNavigation(evt));}}}}
+WebTrends.prototype.dcsRightClick=function(evt){evt=evt||(window.event||"");if(evt){var btn=evt.which||evt.button;if((btn!=1)||(navigator.userAgent.indexOf("Safari")!=-1)){var e=this.dcsEvt(evt,"A");if((typeof(e.href)!="undefined")&&e.href){if((typeof(e.protocol)!="undefined")&&e.protocol&&(e.protocol.indexOf("http")!=-1)){if((typeof(e.pathname)!="undefined")&&this.dcsTypeMatch(e.pathname,this.downloadtypes)){var pth=e.pathname?((e.pathname.indexOf("/")!=0)?"/"+e.pathname:e.pathname):"/";var hn=e.hostname?(e.hostname.split(":")[0]):"";this.dcsMultiTrack("DCS.dcssip",hn,"DCS.dcsuri",pth,"DCS.dcsqry","","WT.ti","RightClick:"+pth,"WT.dl","25");}}}}}}
+WebTrends.prototype.dcsAdv=function(){if(this.trackevents&&(typeof(this.dcsET)=="function")){if(window.addEventListener){window.addEventListener("load",this.dcsET.wtbind(this),false);}
+else if(window.attachEvent){window.attachEvent("onload",this.dcsET.wtbind(this));}}
+this.dcsFPC();}
+WebTrends.prototype.dcsVar=function(){var dCurrent=new Date();var WT=this.WT;var DCS=this.DCS;WT.tz=parseInt(dCurrent.getTimezoneOffset()/60*-1)||"0";WT.bh=dCurrent.getHours()||"0";WT.ul=navigator.appName=="Netscape"?navigator.language:navigator.userLanguage;if(typeof(screen)=="object"){WT.cd=navigator.appName=="Netscape"?screen.pixelDepth:screen.colorDepth;WT.sr=screen.width+"x"+screen.height;}
+if(typeof(navigator.javaEnabled())=="boolean"){WT.jo=navigator.javaEnabled()?"Yes":"No";}
+if(document.title){if(window.RegExp){var tire=new RegExp("^"+window.location.protocol+"//"+window.location.hostname+"\\s-\\s");WT.ti=document.title.replace(tire,"");}
+else{WT.ti=document.title;}}
+WT.js="Yes";WT.jv=(function(){var agt=navigator.userAgent.toLowerCase();var major=parseInt(navigator.appVersion);var mac=(agt.indexOf("mac")!=-1);var ff=(agt.indexOf("firefox")!=-1);var ff0=(agt.indexOf("firefox/0.")!=-1);var ff10=(agt.indexOf("firefox/1.0")!=-1);var ff15=(agt.indexOf("firefox/1.5")!=-1);var ff20=(agt.indexOf("firefox/2.0")!=-1);var ff3up=(ff&&!ff0&&!ff10&!ff15&!ff20);var nn=(!ff&&(agt.indexOf("mozilla")!=-1)&&(agt.indexOf("compatible")==-1));var nn4=(nn&&(major==4));var nn6up=(nn&&(major>=5));var ie=((agt.indexOf("msie")!=-1)&&(agt.indexOf("opera")==-1));var ie4=(ie&&(major==4)&&(agt.indexOf("msie 4")!=-1));var ie5up=(ie&&!ie4);var op=(agt.indexOf("opera")!=-1);var op5=(agt.indexOf("opera 5")!=-1||agt.indexOf("opera/5")!=-1);var op6=(agt.indexOf("opera 6")!=-1||agt.indexOf("opera/6")!=-1);var op7up=(op&&!op5&&!op6);var jv="1.1";if(ff3up){jv="1.8";}
+else if(ff20){jv="1.7";}
+else if(ff15){jv="1.6";}
+else if(ff0||ff10||nn6up||op7up){jv="1.5";}
+else if((mac&&ie5up)||op6){jv="1.4";}
+else if(ie5up||nn4||op5){jv="1.3";}
+else if(ie4){jv="1.2";}
+return jv;})();WT.ct="unknown";if(document.body&&document.body.addBehavior){try{document.body.addBehavior("#default#clientCaps");WT.ct=document.body.connectionType||"unknown";document.body.addBehavior("#default#homePage");WT.hp=document.body.isHomePage(location.href)?"1":"0";}
+catch(e){}}
+if(document.all){WT.bs=document.body?document.body.offsetWidth+"x"+document.body.offsetHeight:"unknown";}
+else{WT.bs=window.innerWidth+"x"+window.innerHeight;}
+WT.fv=(function(){var i,flash;if(window.ActiveXObject){for(i=15;i>0;i--){try{flash=new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+i);return i+".0";}
+catch(e){}}}
+else if(navigator.plugins&&navigator.plugins.length){for(i=0;i<navigator.plugins.length;i++){if(navigator.plugins[i].name.indexOf('Shockwave Flash')!=-1){return navigator.plugins[i].description.split(" ")[2];}}}
+return"Not enabled";})();WT.slv=(function(){var slv="Not enabled";try{if(navigator.userAgent.indexOf('MSIE')!=-1){var sli=new ActiveXObject('AgControl.AgControl');if(sli){slv="Unknown";}}
+else if(navigator.plugins["Silverlight Plug-In"]){slv="Unknown";}}
+catch(e){}
+if(slv!="Not enabled"){var i,m,M,F;if((typeof(Silverlight)=="object")&&(typeof(Silverlight.isInstalled)=="function")){for(i=9;i>0;i--){M=i;if(Silverlight.isInstalled(M+".0")){break;}
+if(slv==M){break;}}
+for(m=9;m>=0;m--){F=M+"."+m;if(Silverlight.isInstalled(F)){slv=F;break;}
+if(slv==F){break;}}}}
+return slv;})();if(this.i18n){if(typeof(document.defaultCharset)=="string"){WT.le=document.defaultCharset;}
+else if(typeof(document.characterSet)=="string"){WT.le=document.characterSet;}
+else{WT.le="unknown";}}
+WT.tv="9.3.0";WT.sp=this.splitvalue;WT.dl="0";WT.ssl=(window.location.protocol.indexOf('https:')==0)?"1":"0";DCS.dcsdat=dCurrent.getTime();DCS.dcssip=window.location.hostname;DCS.dcsuri=window.location.pathname;WT.es=DCS.dcssip+DCS.dcsuri;if(window.location.search){DCS.dcsqry=window.location.search;}
+if(DCS.dcsqry){var dcsqry=DCS.dcsqry.toLowerCase();var params=this.paidsearchparams.length?this.paidsearchparams.toLowerCase().split(","):[];for(var i=0;i<params.length;i++){if(dcsqry.indexOf(params[i]+"=")!=-1){WT.srch="1";break;}}}
+if((window.document.referrer!="")&&(window.document.referrer!="-")){if(!(navigator.appName=="Microsoft Internet Explorer"&&parseInt(navigator.appVersion)<4)){DCS.dcsref=window.document.referrer;}}}
+WebTrends.prototype.dcsEscape=function(S,REL){if(REL!=""){S=S.toString();for(var R in REL){if(REL[R]instanceof RegExp){S=S.replace(REL[R],R);}}
+return S;}
+else{return escape(S);}}
+WebTrends.prototype.dcsA=function(N,V){if(this.i18n&&(this.exre!="")&&!this.exre.test(N)){if(N=="dcsqry"){var newV="";var params=V.substring(1).split("&");for(var i=0;i<params.length;i++){var pair=params[i];var pos=pair.indexOf("=");if(pos!=-1){var key=pair.substring(0,pos);var val=pair.substring(pos+1);if(i!=0){newV+="&";}
+newV+=key+"="+this.dcsEncode(val);}}
+V=V.substring(0,1)+newV;}
+else{V=this.dcsEncode(V);}}
+return"&"+N+"="+this.dcsEscape(V,this.re);}
+WebTrends.prototype.dcsEncode=function(S){return(typeof(encodeURIComponent)=="function")?encodeURIComponent(S):escape(S);}
+WebTrends.prototype.dcsCreateImage=function(dcsSrc){if(document.images){this.images[this.index]=new Image();this.images[this.index].src=dcsSrc;this.index++;}
+else{document.write('<img alt="" border="0" name="DCSIMG" width="1" height="1" src="'+dcsSrc+'">');}}
+WebTrends.prototype.dcsMeta=function(){var elems;if(document.documentElement){elems=document.getElementsByTagName("meta");}
+else if(document.all){elems=document.all.tags("meta");}
+if(typeof(elems)!="undefined"){var length=elems.length;for(var i=0;i<length;i++){var name=elems.item(i).name;var content=elems.item(i).content;var equiv=elems.item(i).httpEquiv;if(name.length>0){if(name.toUpperCase().indexOf("WT.")==0){this.WT[name.substring(3)]=content;}
+else if(name.toUpperCase().indexOf("DCSEXT.")==0){this.DCSext[name.substring(7)]=content;}
+else if(name.toUpperCase().indexOf("DCSDIR.")==0){this.DCSdir[name.substring(7)]=content;}
+else if(name.toUpperCase().indexOf("DCS.")==0){this.DCS[name.substring(4)]=content;}}}}}
+WebTrends.prototype.dcsTag=function(){if(document.cookie.indexOf("WTLOPTOUT=")!=-1||!this.dcsChk()){return;}
+var WT=this.WT;var DCS=this.DCS;var DCSext=this.DCSext;var i18n=this.i18n;var P="http"+(window.location.protocol.indexOf('https:')==0?'s':'')+"://"+this.domain+(this.dcsid==""?'':'/'+this.dcsid)+"/dcs.gif?";if(i18n){WT.dep="";}
+for(var N in DCS){if(DCS[N]&&(typeof DCS[N]!="function")){P+=this.dcsA(N,DCS[N]);}}
+for(N in WT){if(WT[N]&&(typeof WT[N]!="function")){P+=this.dcsA("WT."+N,WT[N]);}}
+for(N in DCSext){if(DCSext[N]&&(typeof DCSext[N]!="function")){if(i18n){WT.dep=(WT.dep.length==0)?N:(WT.dep+";"+N);}
+P+=this.dcsA(N,DCSext[N]);}}
+if(i18n&&(WT.dep.length>0)){P+=this.dcsA("WT.dep",WT.dep);}
+if(P.length>2048&&navigator.userAgent.indexOf('MSIE')>=0){P=P.substring(0,2040)+"&WT.tu=1";}
+this.dcsCreateImage(P);this.WT.ad="";}
+WebTrends.prototype.dcsDebug=function(){var t=this;var i=t.images[0].src;var q=i.indexOf("?");var r=i.substring(0,q).split("/");var m="<b>Protocol</b><br><code>"+r[0]+"<br></code>";m+="<b>Domain</b><br><code>"+r[2]+"<br></code>";m+="<b>Path</b><br><code>/"+r[3]+"/"+r[4]+"<br></code>";m+="<b>Query Params</b><code>"+i.substring(q+1).replace(/\&/g,"<br>")+"</code>";m+="<br><b>Cookies</b><br><code>"+document.cookie.replace(/\;/g,"<br>")+"</code>";if(t.w&&!t.w.closed){t.w.close();}
+t.w=window.open("","dcsDebug","width=500,height=650,scrollbars=yes,resizable=yes");t.w.document.write(m);t.w.focus();}
+WebTrends.prototype.dcsCollect=function(){if(this.enabled){this.dcsVar();this.dcsMeta();this.dcsAdv();this.dcsBounce();if(typeof(this.dcsCustom)=="function"){this.dcsCustom();}
+this.dcsTag();}}
+function dcsMultiTrack(){if(typeof(_tag)!="undefined"){return(_tag.dcsMultiTrack());}}
+function dcsSetVar(){if(typeof(_tag)!="undefined"){return(_tag.dcsSetVar());}}
+function dcsDebug(){if(typeof(_tag)!="undefined"){return(_tag.dcsDebug());}}
+Function.prototype.wtbind=function(obj){var method=this;var temp=function(){return method.apply(obj,arguments);};return temp;}
+WebTrends.prototype.dcsBounce=function(){if(typeof(this.WT.vt_f_s)!="undefined"&&this.WT.vt_f_s==1){this.WT.z_bounce="1";}else{this.WT.z_bounce="0";}}
+WebTrends.prototype.dcsChk=function()
+{if(this.rate==100){return"true";}
+var cname='wtspl';cval=this.dcsGetCookie(cname);if(cval==null)
+{cval=Math.floor(Math.random()*1000000);var date=new Date();date.setTime(date.getTime()+(30*24*60*60*1000));document.cookie=cname+"="+cval+"; expires="+date.toGMTString()+"; path=/; domain="+this.fpcdom+";";}
+return((cval%1000)<(this.rate*10));} \ No newline at end of file
diff --git a/extensions/BMO/web/producticons/component.png b/extensions/BMO/web/producticons/component.png
new file mode 100644
index 000000000..b9c5053f6
--- /dev/null
+++ b/extensions/BMO/web/producticons/component.png
Binary files differ
diff --git a/extensions/BMO/web/producticons/dino.png b/extensions/BMO/web/producticons/dino.png
new file mode 100644
index 000000000..9e0470a07
--- /dev/null
+++ b/extensions/BMO/web/producticons/dino.png
Binary files differ
diff --git a/extensions/BMO/web/producticons/firefox.png b/extensions/BMO/web/producticons/firefox.png
new file mode 100644
index 000000000..3ba536ed2
--- /dev/null
+++ b/extensions/BMO/web/producticons/firefox.png
Binary files differ
diff --git a/extensions/BMO/web/producticons/firefox_android.png b/extensions/BMO/web/producticons/firefox_android.png
new file mode 100644
index 000000000..7f9329082
--- /dev/null
+++ b/extensions/BMO/web/producticons/firefox_android.png
Binary files differ
diff --git a/extensions/BMO/web/producticons/firefox_os.png b/extensions/BMO/web/producticons/firefox_os.png
new file mode 100644
index 000000000..5f08dc4f9
--- /dev/null
+++ b/extensions/BMO/web/producticons/firefox_os.png
Binary files differ
diff --git a/extensions/BMO/web/producticons/input.png b/extensions/BMO/web/producticons/input.png
new file mode 100644
index 000000000..81f355d85
--- /dev/null
+++ b/extensions/BMO/web/producticons/input.png
Binary files differ
diff --git a/extensions/BMO/web/producticons/localization.png b/extensions/BMO/web/producticons/localization.png
new file mode 100644
index 000000000..df3eac2d0
--- /dev/null
+++ b/extensions/BMO/web/producticons/localization.png
Binary files differ
diff --git a/extensions/BMO/web/producticons/marketplace.png b/extensions/BMO/web/producticons/marketplace.png
new file mode 100644
index 000000000..62025a2a8
--- /dev/null
+++ b/extensions/BMO/web/producticons/marketplace.png
Binary files differ
diff --git a/extensions/BMO/web/producticons/other.png b/extensions/BMO/web/producticons/other.png
new file mode 100644
index 000000000..e436c22ae
--- /dev/null
+++ b/extensions/BMO/web/producticons/other.png
Binary files differ
diff --git a/extensions/BMO/web/producticons/seamonkey.png b/extensions/BMO/web/producticons/seamonkey.png
new file mode 100644
index 000000000..fcb261ae1
--- /dev/null
+++ b/extensions/BMO/web/producticons/seamonkey.png
Binary files differ
diff --git a/extensions/BMO/web/producticons/sync.png b/extensions/BMO/web/producticons/sync.png
new file mode 100644
index 000000000..b42125ef6
--- /dev/null
+++ b/extensions/BMO/web/producticons/sync.png
Binary files differ
diff --git a/extensions/BMO/web/producticons/thunderbird.png b/extensions/BMO/web/producticons/thunderbird.png
new file mode 100644
index 000000000..f3523183a
--- /dev/null
+++ b/extensions/BMO/web/producticons/thunderbird.png
Binary files differ
diff --git a/extensions/BMO/web/producticons/webmaker.png b/extensions/BMO/web/producticons/webmaker.png
new file mode 100644
index 000000000..d576a5f01
--- /dev/null
+++ b/extensions/BMO/web/producticons/webmaker.png
Binary files differ
diff --git a/extensions/BMO/web/styles/choose_product.css b/extensions/BMO/web/styles/choose_product.css
new file mode 100644
index 000000000..053af542f
--- /dev/null
+++ b/extensions/BMO/web/styles/choose_product.css
@@ -0,0 +1,16 @@
+/* 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. */
+
+#choose_product h2,
+#choose_product p {
+ text-align: center;
+}
+
+#choose_product td h2,
+#choose_product td p {
+ text-align: left;
+}
diff --git a/extensions/BMO/web/styles/create_account.css b/extensions/BMO/web/styles/create_account.css
new file mode 100644
index 000000000..0ab527629
--- /dev/null
+++ b/extensions/BMO/web/styles/create_account.css
@@ -0,0 +1,62 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * 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
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Byron Jones <glob@mozilla.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#create-account h2 {
+ margin: 0px;
+}
+
+.column-header {
+ padding: 20px 20px 20px 0px;
+}
+
+#create-account-left {
+ border-right: 2px solid #888888;
+ padding-right: 10px;
+}
+
+#product-list td {
+ padding-top: 10px;
+}
+
+#product-list img {
+ padding-right: 10px;
+}
+
+#create-account-right {
+ padding-left: 10px;
+}
+
+#right-blurb {
+ font-size: large;
+}
+
+#right-blurb li {
+ padding-bottom: 1em;
+}
+
+#create-account-right {
+ padding-bottom: 5em;
+}
+
diff --git a/extensions/BMO/web/styles/edit_bug.css b/extensions/BMO/web/styles/edit_bug.css
new file mode 100644
index 000000000..24212270d
--- /dev/null
+++ b/extensions/BMO/web/styles/edit_bug.css
@@ -0,0 +1,49 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * 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 BMO Bugzilla Extension;
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011 the
+ * Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Byron Jones <glob@mozilla.com>
+ *
+ * ***** END LICENSE BLOCK *****
+ */
+
+#project-flags,
+#custom-flags {
+ width: auto;
+}
+
+.bz_hidden {
+ display: none;
+}
+
+.bz_collapse_comment {
+ font-family: monospace;
+}
+
+#prod_desc_container,
+#comp_desc_container {
+ overflow: auto;
+ color: green;
+ padding: 2px;
+}
+
+#toggle_prod_desc,
+#toggle_comp_desc {
+ white-space: nowrap;
+}
diff --git a/extensions/BMO/web/styles/reports.css b/extensions/BMO/web/styles/reports.css
new file mode 100644
index 000000000..06ae52d68
--- /dev/null
+++ b/extensions/BMO/web/styles/reports.css
@@ -0,0 +1,75 @@
+.hidden {
+ display: none;
+}
+
+#product, #component {
+ width: 20em;
+}
+
+#parameters th {
+ text-align: left;
+ vertical-align: middle !important;
+}
+
+#report tr.bugitem:hover {
+ background: #ccccff;
+}
+
+#report td, #report th {
+ padding: 3px 10px 3px 3px;
+}
+
+#report th {
+ text-align: left;
+}
+
+#report th.right {
+ text-align: right;
+}
+
+#report th.sorted {
+ text-decoration: underline;
+}
+
+#report-header {
+ background-color: #cccccc;
+}
+
+.report_subheader {
+ background-color: #dddddd;
+}
+
+.report_row_odd {
+ background-color: #eeeeee;
+ color: #000000;
+}
+
+.report_row_even {
+ background-color: #ffffff;
+ color: #000000;
+}
+
+#report.hover tr:hover {
+ background-color: #ccccff;
+}
+
+#report {
+ border: 1px solid #888888;
+}
+
+#report th, #report td {
+ border: 0px;
+}
+
+.disabled {
+ color: #888888;
+}
+
+.hoverrow tr:hover {
+ background-color: #ccccff;
+}
+
+.problem {
+ color: #aa2222;
+}
+
diff --git a/extensions/BMO/web/styles/triage_reports.css b/extensions/BMO/web/styles/triage_reports.css
new file mode 100644
index 000000000..6190fd32c
--- /dev/null
+++ b/extensions/BMO/web/styles/triage_reports.css
@@ -0,0 +1,23 @@
+.hidden {
+ display: none;
+}
+
+#triage_form th {
+ text-align: left;
+}
+
+#product, #component {
+ width: 20em;
+}
+
+#report tr.bugitem:hover {
+ background: #ccccff;
+}
+
+#report td {
+ padding: 1px 10px 1px 10px;
+}
+
+#report-header {
+ background: #dddddd;
+}
diff --git a/extensions/BMO/web/yui-history-iframe.txt b/extensions/BMO/web/yui-history-iframe.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/extensions/BMO/web/yui-history-iframe.txt