summaryrefslogtreecommitdiffstats
path: root/extensions/BMO
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/BMO')
-rw-r--r--extensions/BMO/Config.pm21
-rw-r--r--extensions/BMO/Extension.pm4648
-rwxr-xr-xextensions/BMO/bin/bug_1022707.pl6
-rwxr-xr-xextensions/BMO/bin/bug_1093952.pl52
-rwxr-xr-xextensions/BMO/bin/bug_1141452.pl110
-rwxr-xr-xextensions/BMO/bin/migrate-github-pull-requests.pl67
-rw-r--r--extensions/BMO/lib/Constants.pm6
-rw-r--r--extensions/BMO/lib/Data.pm403
-rw-r--r--extensions/BMO/lib/FakeBug.pm28
-rw-r--r--extensions/BMO/lib/Reports/Groups.pm485
-rw-r--r--extensions/BMO/lib/Reports/Internship.pm135
-rw-r--r--extensions/BMO/lib/Reports/ProductSecurity.pm76
-rw-r--r--extensions/BMO/lib/Reports/Recruiting.pm126
-rw-r--r--extensions/BMO/lib/Reports/ReleaseTracking.pm779
-rw-r--r--extensions/BMO/lib/Reports/Triage.pm516
-rw-r--r--extensions/BMO/lib/Reports/UserActivity.pm382
-rw-r--r--extensions/BMO/lib/Util.pm111
-rw-r--r--extensions/BMO/lib/WebService.pm68
-rw-r--r--extensions/BMO/t/bounty_attachment.t93
19 files changed, 4066 insertions, 4046 deletions
diff --git a/extensions/BMO/Config.pm b/extensions/BMO/Config.pm
index 153af24cb..e185b0b5d 100644
--- a/extensions/BMO/Config.pm
+++ b/extensions/BMO/Config.pm
@@ -28,24 +28,11 @@ use warnings;
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'
- },
+ {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 => [
-];
+use constant OPTIONAL_MODULES => [];
__PACKAGE__->NAME;
diff --git a/extensions/BMO/Extension.pm b/extensions/BMO/Extension.pm
index 7499f0d1c..f4fb6fa32 100644
--- a/extensions/BMO/Extension.pm
+++ b/extensions/BMO/Extension.pm
@@ -72,296 +72,304 @@ our $VERSION = '0.1';
#
BEGIN {
- *Bugzilla::Bug::last_closed_date = \&_last_closed_date;
- *Bugzilla::Bug::reporters_hw_os = \&_bug_reporters_hw_os;
- *Bugzilla::Bug::is_unassigned = \&_bug_is_unassigned;
- *Bugzilla::Bug::has_current_patch = \&_bug_has_current_patch;
- *Bugzilla::Bug::missing_sec_approval = \&_bug_missing_sec_approval;
- *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::Product::default_platform_id = \&_product_default_platform_id;
- *Bugzilla::Product::default_op_sys_id = \&_product_default_op_sys_id;
- *Bugzilla::Product::default_platform = \&_product_default_platform;
- *Bugzilla::Product::default_op_sys = \&_product_default_op_sys;
- *Bugzilla::check_default_product_security_group = \&_check_default_product_security_group;
- *Bugzilla::Attachment::is_bounty_attachment = \&_attachment_is_bounty_attachment;
- *Bugzilla::Attachment::bounty_details = \&_attachment_bounty_details;
- *Bugzilla::Attachment::external_redirect = \&_attachment_external_redirect;
- *Bugzilla::Attachment::can_review = \&_attachment_can_review;
- *Bugzilla::Attachment::fetch_github_pr_diff = \&_attachment_fetch_github_pr_diff;
+ *Bugzilla::Bug::last_closed_date = \&_last_closed_date;
+ *Bugzilla::Bug::reporters_hw_os = \&_bug_reporters_hw_os;
+ *Bugzilla::Bug::is_unassigned = \&_bug_is_unassigned;
+ *Bugzilla::Bug::has_current_patch = \&_bug_has_current_patch;
+ *Bugzilla::Bug::missing_sec_approval = \&_bug_missing_sec_approval;
+ *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::Product::default_platform_id = \&_product_default_platform_id;
+ *Bugzilla::Product::default_op_sys_id = \&_product_default_op_sys_id;
+ *Bugzilla::Product::default_platform = \&_product_default_platform;
+ *Bugzilla::Product::default_op_sys = \&_product_default_op_sys;
+ *Bugzilla::check_default_product_security_group
+ = \&_check_default_product_security_group;
+ *Bugzilla::Attachment::is_bounty_attachment
+ = \&_attachment_is_bounty_attachment;
+ *Bugzilla::Attachment::bounty_details = \&_attachment_bounty_details;
+ *Bugzilla::Attachment::external_redirect = \&_attachment_external_redirect;
+ *Bugzilla::Attachment::can_review = \&_attachment_can_review;
+ *Bugzilla::Attachment::fetch_github_pr_diff
+ = \&_attachment_fetch_github_pr_diff;
}
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);
- }
+ 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',
+ );
- $vars->{'order_columns'} = \@order_columns;
+ my @orderstrings = split(/,\s*/, $vars->{'order'});
- # 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);
+ # 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);
+ }
- 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->{'order_columns'} = \@order_columns;
- $vars->{'columns_sortkey'} = \%columns_sortkey;
+ # 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);
}
- 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') || "";
- }
+ $columns_sortkey{'target_milestone'} = _get_field_values_sort_key('milestones');
- # Purpose: for pretty product chooser
- $vars->{'format'} = Bugzilla->cgi->param('format');
+ $vars->{'columns_sortkey'} = \%columns_sortkey;
+ }
+ elsif ($file =~ /^bug\/create\/create[\.-](.*)/) {
+ my $format = $1;
+ if (!$vars->{'cloned_bug_id'}) {
- if ($format eq 'doc.html.tmpl') {
- my $versions = Bugzilla::Product->new({ name => 'Core' })->versions;
- $vars->{'versions'} = [ reverse @$versions ];
- }
- }
- elsif ($file eq 'bug/edit.html.tmpl' || $file eq 'bug_modal/edit.html.tmpl') {
- $vars->{split_cf_crash_signature} = $self->_split_crash_signature($vars);
+ # 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 ($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 ($format eq 'doc.html.tmpl') {
+ my $versions = Bugzilla::Product->new({name => 'Core'})->versions;
+ $vars->{'versions'} = [reverse @$versions];
}
+ }
+ elsif ($file eq 'bug/edit.html.tmpl' || $file eq 'bug_modal/edit.html.tmpl') {
+ $vars->{split_cf_crash_signature} = $self->_split_crash_signature($vars);
+ }
- if ($file =~ /^attachment\/diff-header\./) {
- my $attachid = $vars->{attachid} ? $vars->{attachid} : $vars->{newid};
- $vars->{attachment} = Bugzilla::Attachment->new({ id => $attachid, cache => 1 })
- if $attachid;
- }
- if ($file =~ /^admin\/products\/(create|edit)\./) {
- my $product = $vars->{product};
- my $security_groups = Bugzilla::Group->match({ isbuggroup => 1, isactive => 1 });
- if ($product) {
- # If set group is not active currently, we add it into the list
- if (!grep($_->name eq $product->default_security_group, @$security_groups)) {
- push(@$security_groups, $product->default_security_group_obj);
- @$security_groups = sort { $a->name cmp $b->name } @$security_groups;
- }
- }
- $vars->{security_groups} = $security_groups;
- }
-}
+ if ($file =~ /^list\/list/ || $file =~ /^bug\/create\/create[\.-]/) {
-sub page_before_template {
- my ($self, $args) = @_;
- my $page = $args->{'page_id'};
- my $vars = $args->{'vars'};
+ # 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 ($page eq 'user_activity.html') {
- require Bugzilla::Extension::BMO::Reports::UserActivity;
- Bugzilla::Extension::BMO::Reports::UserActivity::report($vars);
+ if ($file =~ /^attachment\/diff-header\./) {
+ my $attachid = $vars->{attachid} ? $vars->{attachid} : $vars->{newid};
+ $vars->{attachment} = Bugzilla::Attachment->new({id => $attachid, cache => 1})
+ if $attachid;
+ }
+ if ($file =~ /^admin\/products\/(create|edit)\./) {
+ my $product = $vars->{product};
+ my $security_groups = Bugzilla::Group->match({isbuggroup => 1, isactive => 1});
+ if ($product) {
+
+ # If set group is not active currently, we add it into the list
+ if (!grep($_->name eq $product->default_security_group, @$security_groups)) {
+ push(@$security_groups, $product->default_security_group_obj);
+ @$security_groups = sort { $a->name cmp $b->name } @$security_groups;
+ }
}
- elsif ($page eq 'triage_reports.html') {
- require Bugzilla::Extension::BMO::Reports::Triage;
- Bugzilla::Extension::BMO::Reports::Triage::unconfirmed($vars);
- }
- elsif ($page eq 'triage_owners.html') {
- require Bugzilla::Extension::BMO::Reports::Triage;
- Bugzilla::Extension::BMO::Reports::Triage::owners($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($page, $vars);
- }
- elsif ($page eq 'recruiting_dashboard.html') {
- require Bugzilla::Extension::BMO::Reports::Recruiting;
- Bugzilla::Extension::BMO::Reports::Recruiting::report($vars);
- }
- elsif ($page eq 'internship_dashboard.html') {
- require Bugzilla::Extension::BMO::Reports::Internship;
- Bugzilla::Extension::BMO::Reports::Internship::report($vars);
- }
- elsif ($page eq 'email_queue.html') {
- print Bugzilla->cgi->redirect('view_job_queue.cgi');
- }
- 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);
- }
- elsif ($page eq 'attachment_bounty_form.html') {
- bounty_attachment($vars);
- }
- elsif ($page eq 'triage_request.html') {
- triage_request($vars);
- }
+ $vars->{security_groups} = $security_groups;
+ }
+}
+
+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::unconfirmed($vars);
+ }
+ elsif ($page eq 'triage_owners.html') {
+ require Bugzilla::Extension::BMO::Reports::Triage;
+ Bugzilla::Extension::BMO::Reports::Triage::owners($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($page, $vars);
+ }
+ elsif ($page eq 'recruiting_dashboard.html') {
+ require Bugzilla::Extension::BMO::Reports::Recruiting;
+ Bugzilla::Extension::BMO::Reports::Recruiting::report($vars);
+ }
+ elsif ($page eq 'internship_dashboard.html') {
+ require Bugzilla::Extension::BMO::Reports::Internship;
+ Bugzilla::Extension::BMO::Reports::Internship::report($vars);
+ }
+ elsif ($page eq 'email_queue.html') {
+ print Bugzilla->cgi->redirect('view_job_queue.cgi');
+ }
+ 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);
+ }
+ elsif ($page eq 'attachment_bounty_form.html') {
+ bounty_attachment($vars);
+ }
+ elsif ($page eq 'triage_request.html') {
+ triage_request($vars);
+ }
}
sub bounty_attachment {
- my ($vars) = @_;
-
- my $user = Bugzilla->user;
- $user->in_group('bounty-team')
- || ThrowUserError("auth_failure", { group => "bounty-team",
- action => "add",
- object => "bounty_attachments" });
-
- my $input = Bugzilla->input_params;
- my $dbh = Bugzilla->dbh;
- my $bug = Bugzilla::Bug->check({ id => $input->{bug_id}, cache => 1 });
- my $attachment = first { $_ && _attachment_is_bounty_attachment($_) } @{$bug->attachments};
- $vars->{bug} = $bug;
-
- if ($input->{submit}) {
- ThrowUserError('bounty_attachment_missing_reporter')
- unless $input->{reporter_email};
-
- check_hash_token($input->{token}, ['bounty', $bug->id]);
-
- my @fields = qw( reporter_email amount_paid reported_date fixed_date awarded_date publish );
- my %form = map { $_ => $input->{$_} } @fields;
- $form{credit} = [ grep { defined } map { $input->{"credit_$_"} } 1..3 ];
-
- $dbh->bz_start_transaction();
- if ($attachment) {
- $attachment->set(
- description => format_bounty_attachment_description(\%form)
- );
- $attachment->update;
- }
- else {
- my $attachment = Bugzilla::Attachment->create({
- bug => $bug,
- isprivate => 1,
- mimetype => 'text/plain',
- data => 'bounty',
- filename => 'bugbounty.data',
- description => format_bounty_attachment_description(\%form),
- });
- }
- $dbh->bz_commit_transaction();
+ my ($vars) = @_;
- Bugzilla::BugMail::Send($bug->id, { changer => $user });
+ my $user = Bugzilla->user;
+ $user->in_group('bounty-team')
+ || ThrowUserError("auth_failure",
+ {group => "bounty-team", action => "add", object => "bounty_attachments"});
- print Bugzilla->cgi->redirect('show_bug.cgi?id=' . $bug->id);
- exit;
- }
+ my $input = Bugzilla->input_params;
+ my $dbh = Bugzilla->dbh;
+ my $bug = Bugzilla::Bug->check({id => $input->{bug_id}, cache => 1});
+ my $attachment
+ = first { $_ && _attachment_is_bounty_attachment($_) } @{$bug->attachments};
+ $vars->{bug} = $bug;
+
+ if ($input->{submit}) {
+ ThrowUserError('bounty_attachment_missing_reporter')
+ unless $input->{reporter_email};
+
+ check_hash_token($input->{token}, ['bounty', $bug->id]);
+
+ my @fields
+ = qw( reporter_email amount_paid reported_date fixed_date awarded_date publish );
+ my %form = map { $_ => $input->{$_} } @fields;
+ $form{credit} = [grep {defined} map { $input->{"credit_$_"} } 1 .. 3];
+ $dbh->bz_start_transaction();
if ($attachment) {
- $vars->{form} = $attachment->bounty_details;
+ $attachment->set(description => format_bounty_attachment_description(\%form));
+ $attachment->update;
}
else {
- my $now = $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
- $vars->{form} = {
- reporter_email => $bug->reporter->email,
- reported_date => format_time($bug->creation_ts, "%Y-%m-%d"),
- awarded_date => format_time($now, "%Y-%m-%d"),
- publish => 1
- };
- if ($bug->cf_last_resolved) {
- $vars->{form}{fixed_date} = format_time($bug->cf_last_resolved, "%Y-%m-%d"),
- }
+ my $attachment = Bugzilla::Attachment->create({
+ bug => $bug,
+ isprivate => 1,
+ mimetype => 'text/plain',
+ data => 'bounty',
+ filename => 'bugbounty.data',
+ description => format_bounty_attachment_description(\%form),
+ });
+ }
+ $dbh->bz_commit_transaction();
+
+ Bugzilla::BugMail::Send($bug->id, {changer => $user});
+
+ print Bugzilla->cgi->redirect('show_bug.cgi?id=' . $bug->id);
+ exit;
+ }
+
+ if ($attachment) {
+ $vars->{form} = $attachment->bounty_details;
+ }
+ else {
+ my $now = $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
+ $vars->{form} = {
+ reporter_email => $bug->reporter->email,
+ reported_date => format_time($bug->creation_ts, "%Y-%m-%d"),
+ awarded_date => format_time($now, "%Y-%m-%d"),
+ publish => 1
+ };
+ if ($bug->cf_last_resolved) {
+ $vars->{form}{fixed_date} = format_time($bug->cf_last_resolved, "%Y-%m-%d"),;
}
- $vars->{form}{token} = issue_hash_token(['bounty', $bug->id]);
+ }
+ $vars->{form}{token} = issue_hash_token(['bounty', $bug->id]);
}
sub _attachment_is_bounty_attachment {
- my ($attachment) = @_;
+ my ($attachment) = @_;
- return 0 unless $attachment->filename eq 'bugbounty.data';
- return 0 unless $attachment->contenttype eq 'text/plain';
- return 0 unless $attachment->isprivate;
- return 0 unless $attachment->attacher->in_group('bounty-team');
+ return 0 unless $attachment->filename eq 'bugbounty.data';
+ return 0 unless $attachment->contenttype eq 'text/plain';
+ return 0 unless $attachment->isprivate;
+ return 0 unless $attachment->attacher->in_group('bounty-team');
- return $attachment->description =~ /^(?:[^,]*,)+[^,]*$/;
+ return $attachment->description =~ /^(?:[^,]*,)+[^,]*$/;
}
sub _attachment_bounty_details {
- my ($attachment) = @_;
- if (!exists $attachment->{bounty_details}) {
- if ($attachment->is_bounty_attachment) {
- $attachment->{bounty_details} = parse_bounty_attachment_description($attachment->description);
- }
- else {
- $attachment->{bounty_details} = undef;
- }
+ my ($attachment) = @_;
+ if (!exists $attachment->{bounty_details}) {
+ if ($attachment->is_bounty_attachment) {
+ $attachment->{bounty_details}
+ = parse_bounty_attachment_description($attachment->description);
+ }
+ else {
+ $attachment->{bounty_details} = undef;
}
- return $attachment->{bounty_details};
+ }
+ return $attachment->{bounty_details};
}
sub format_bounty_attachment_description {
- my ($form) = @_;
- my @fields = (
- @$form{qw( reporter_email amount_paid reported_date fixed_date awarded_date )},
- $form->{publish} ? 'true' : 'false',
- @{ $form->{credit} // [] }
- );
+ my ($form) = @_;
+ my @fields = (
+ @$form{qw( reporter_email amount_paid reported_date fixed_date awarded_date )},
+ $form->{publish} ? 'true' : 'false',
+ @{$form->{credit} // []}
+ );
- return join(',', map { $_ // '' } @fields);
+ return join(',', map { $_ // '' } @fields);
}
sub parse_bounty_attachment_description {
- my ($desc) = @_;
+ my ($desc) = @_;
- my %map = ( true => 1, false => 0 );
- my $date = qr/\d{4}-\d{2}-\d{2}/;
- $desc =~ m!
+ my %map = (true => 1, false => 0);
+ my $date = qr/\d{4}-\d{2}-\d{2}/;
+ $desc =~ m!
^
(?<reporter_email> [^,]+) \s*,\s*
(?<amount_paid> [0-9]+[-+?]?) ? \s*,\s*
@@ -373,1799 +381,1830 @@ sub parse_bounty_attachment_description {
$
!x;
- return {
- reporter_email => $+{reporter_email} // '',
- amount_paid => $+{amount_paid} // '',
- reported_date => $+{reported_date} // '',
- fixed_date => $+{fixed_date} // '',
- awarded_date => $+{awarded_date} // '',
- publish => $map{ $+{publish} // 'false' },
- credit => [grep { $_ } split(/\s*,\s*/, $+{credits}) ]
- };
+ return {
+ reporter_email => $+{reporter_email} // '',
+ amount_paid => $+{amount_paid} // '',
+ reported_date => $+{reported_date} // '',
+ fixed_date => $+{fixed_date} // '',
+ awarded_date => $+{awarded_date} // '',
+ publish => $map{$+{publish} // 'false'},
+ credit => [grep {$_} split(/\s*,\s*/, $+{credits})]
+ };
}
sub triage_request {
- my ($vars) = @_;
- my $user = Bugzilla->login(LOGIN_REQUIRED);
- if (Bugzilla->input_params->{update}) {
- Bugzilla->set_user(Bugzilla::User->super_user);
- $user->set_groups({ add => [ 'canconfirm' ] });
- Bugzilla->set_user($user);
- $user->update();
- $vars->{updated} = 1;
- }
+ my ($vars) = @_;
+ my $user = Bugzilla->login(LOGIN_REQUIRED);
+ if (Bugzilla->input_params->{update}) {
+ Bugzilla->set_user(Bugzilla::User->super_user);
+ $user->set_groups({add => ['canconfirm']});
+ Bugzilla->set_user($user);
+ $user->update();
+ $vars->{updated} = 1;
+ }
}
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;
+ 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'};
+ my ($self, $args) = @_;
+ my $fields = $args->{'fields'};
+ my $params = $args->{'params'};
+ my $product = $params->{'product'};
+ my $component = $params->{'component'};
- return if !$product;
+ return if !$product;
- my $product_name = blessed $product ? $product->name : $product;
- my $component_name = blessed $component ? $component->name : $component;
+ 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;
+ 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, $bug) = @_;
-
- # check bugzilla's built-in visibility controls first
- if ($bug) {
- my $field = Bugzilla::Field->new({ name => $field_name, cache => 1 });
- return 1 if $field && !$field->is_visible_on_bug($bug);
- }
-
- # 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;
- }
+ my ($field_name, $product_name, $component_name, $bug) = @_;
+
+ # check bugzilla's built-in visibility controls first
+ if ($bug) {
+ my $field = Bugzilla::Field->new({name => $field_name, cache => 1});
+ return 1 if $field && !$field->is_visible_on_bug($bug);
+ }
+
+ # 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;
+ }
}
- return 1;
+ 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;
+ 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);
- }
- }
+ 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) = @_;
+ my ($group, $recipients) = @_;
- return if !$group;
+ 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();
- }
+ 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 ($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);
+ 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 !~ /\?$/;
+ 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 '---') {
- # Cannot use the standard %cf_setter mapping as we want anyone
- # to be able to set ?, just not the other values.
- if ($field eq 'cf_cab_review') {
- if ($new_value ne '1'
- && $new_value ne '?'
- && !$user->in_group('infra', $bug->product_id))
- {
- push (@$priv_results, PRIVILEGES_REQUIRED_EMPOWERED);
- }
- }
- # "other" custom field setters restrictions
- elsif (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);
- }
+ 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 '---') {
+
+ # Cannot use the standard %cf_setter mapping as we want anyone
+ # to be able to set ?, just not the other values.
+ if ($field eq 'cf_cab_review') {
+ if ( $new_value ne '1'
+ && $new_value ne '?'
+ && !$user->in_group('infra', $bug->product_id))
+ {
+ push(@$priv_results, PRIVILEGES_REQUIRED_EMPOWERED);
+ }
+ }
+
+ # "other" custom field setters restrictions
+ elsif (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 'EXPIRED') {
- } 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);
- }
+ # 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 '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 ($field eq 'resolution' && $new_value eq 'FIXED') {
- } 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' ||
- ($old_value eq '' && $new_value eq '1')))
- {
- push (@$priv_results, PRIVILEGES_REQUIRED_NONE);
- }
- elsif ($field eq 'dup_id') {
- push (@$priv_results, PRIVILEGES_REQUIRED_NONE);
- }
+ # 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') {
- # 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);
- }
- }
+ }
+ 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'
+ || ($old_value eq '' && $new_value eq '1'))
+ )
+ {
+ push(@$priv_results, PRIVILEGES_REQUIRED_NONE);
+ }
+ elsif ($field eq 'dup_id') {
+ 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'};
+ 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}\-
+ # 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}|[1-9]\d{4,})(?!\d))\b/,
- replace => sub {
- my $args = shift;
- my $match = html_quote($args->{matches}->[0]);
- return qq{<a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=$match">$match</a>};
- }
- });
-
- # link to svn.m.o
- push (@$regexes, {
- match => qr/(^|\s)r(\d{4,})\b/,
- replace => sub {
- my $args = shift;
- my $match = html_quote($args->{matches}->[1]);
- return
- $args->{matches}->[0] .
- qq{<a href="https://viewvc.svn.mozilla.org/vc?view=rev&amp;revision=$match">r$match</a>};
- }
- });
-
- # link old git.mozilla.org commit messages to github
- push (@$regexes, {
- match => qr#^(To\s(?:ssh://)?(?:[^\@]+\@)?git\.mozilla\.org[:/](.+?\.git)\n
+ 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}|[1-9]\d{4,})(?!\d))\b/,
+ replace => sub {
+ my $args = shift;
+ my $match = html_quote($args->{matches}->[0]);
+ return
+ qq{<a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=$match">$match</a>};
+ }
+ }
+ );
+
+ # link to svn.m.o
+ push(
+ @$regexes,
+ {
+ match => qr/(^|\s)r(\d{4,})\b/,
+ replace => sub {
+ my $args = shift;
+ my $match = html_quote($args->{matches}->[1]);
+ return $args->{matches}->[0]
+ . qq{<a href="https://viewvc.svn.mozilla.org/vc?view=rev&amp;revision=$match">r$match</a>};
+ }
+ }
+ );
+
+ # link old git.mozilla.org commit messages to github
+ 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 = html_quote($args->{matches}->[2]);
- my $revision = html_quote($args->{matches}->[3]);
- $repo = 'mozilla/webtools-bmo-bugzilla' if $repo =~ /^webtools\/bmo\/bugzilla/;
- $repo = 'bugzilla/bugzilla' if $repo =~ /^bugzilla\/bugzilla\.git/;
- $repo = 'bugzilla/bugzilla.org' if $repo =~ /^www\/bugzilla\.org/;
- return qq#$preamble<a href="https://github.com/$repo/commit/$revision">$text</a>#;
- }
- });
-
- # link github commit messages
- push (@$regexes, {
- match => qr#^(To\s(?:https://|git@)?github\.com[:/](.+?)\.git\n
+ replace => sub {
+ my $args = shift;
+ my $preamble = html_quote($args->{matches}->[0]);
+ my $repo = html_quote($args->{matches}->[1]);
+ my $text = html_quote($args->{matches}->[2]);
+ my $revision = html_quote($args->{matches}->[3]);
+ $repo = 'mozilla/webtools-bmo-bugzilla' if $repo =~ /^webtools\/bmo\/bugzilla/;
+ $repo = 'bugzilla/bugzilla' if $repo =~ /^bugzilla\/bugzilla\.git/;
+ $repo = 'bugzilla/bugzilla.org' if $repo =~ /^www\/bugzilla\.org/;
+ return
+ qq#$preamble<a href="https://github.com/$repo/commit/$revision">$text</a>#;
+ }
+ }
+ );
+
+ # link github commit messages
+ push(
+ @$regexes,
+ {
+ match => qr#^(To\s(?:https://|git@)?github\.com[:/](.+?)\.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 = html_quote($args->{matches}->[2]);
- my $revision = html_quote($args->{matches}->[3]);
- return qq#$preamble<a href="https://github.com/$repo/commit/$revision">$text</a>#;
- }
- });
-
- # link github pull requests and issues
- push (@$regexes, {
- match => qr/(\s)([A-Za-z0-9_\.-]+)\/([A-Za-z0-9_\.-]+)\#([0-9]+)\b/,
- replace => sub {
- my $args = shift;
- my $owner = html_quote($args->{matches}->[1]);
- my $repo = html_quote($args->{matches}->[2]);
- my $number = html_quote($args->{matches}->[3]);
- return qq# <a href="https://github.com/$owner/$repo/issues/$number">$owner/$repo\#$number</a>#;
+ replace => sub {
+ my $args = shift;
+ my $preamble = html_quote($args->{matches}->[0]);
+ my $repo = html_quote($args->{matches}->[1]);
+ my $text = html_quote($args->{matches}->[2]);
+ my $revision = html_quote($args->{matches}->[3]);
+ return
+ qq#$preamble<a href="https://github.com/$repo/commit/$revision">$text</a>#;
+ }
+ }
+ );
+
+ # link github pull requests and issues
+ push(
+ @$regexes,
+ {
+ match => qr/(\s)([A-Za-z0-9_\.-]+)\/([A-Za-z0-9_\.-]+)\#([0-9]+)\b/,
+ replace => sub {
+ my $args = shift;
+ my $owner = html_quote($args->{matches}->[1]);
+ my $repo = html_quote($args->{matches}->[2]);
+ my $number = html_quote($args->{matches}->[3]);
+ return
+ qq# <a href="https://github.com/$owner/$repo/issues/$number">$owner/$repo\#$number</a>#;
+ }
+ }
+ );
+
+# Update certain links to git.mozilla.org to go to github.com instead
+# https://git.mozilla.org/?p=webtools/bmo/bugzilla.git;a=blob;f=Bugzilla/WebService/Bug.pm;h=d7a1d8f9bb5fdee524f2bb342a4573a63d890f2e;hb=HEAD#l657
+ push(
+ @$regexes,
+ {
+ match => qr#\b(https?://git\.mozilla\.org\S+)\b#mx,
+ replace => sub {
+ my $args = shift;
+ my $match = $args->{matches}->[0];
+ my $uri = URI->new($match);
+ my $text = html_quote($match);
+
+ # Only work on BMO and Bugzilla repos
+ my $repo = html_quote($uri->query_param_delete("p")) || '';
+ if ($repo !~ /(webtools\/bmo|bugzilla)\//) {
+ return qq#<a href="$text">$text</a>#;
}
- });
-
- # Update certain links to git.mozilla.org to go to github.com instead
- # https://git.mozilla.org/?p=webtools/bmo/bugzilla.git;a=blob;f=Bugzilla/WebService/Bug.pm;h=d7a1d8f9bb5fdee524f2bb342a4573a63d890f2e;hb=HEAD#l657
- push(@$regexes, {
- match => qr#\b(https?://git\.mozilla\.org\S+)\b#mx,
- replace => sub {
- my $args = shift;
- my $match = $args->{matches}->[0];
- my $uri = URI->new($match);
- my $text = html_quote($match);
-
- # Only work on BMO and Bugzilla repos
- my $repo = html_quote($uri->query_param_delete("p")) || '';
- if ($repo !~ /(webtools\/bmo|bugzilla)\//) {
- return qq#<a href="$text">$text</a>#;
- }
- my $action = html_quote($uri->query_param_delete("a")) || '';
- my $file = html_quote($uri->query_param_delete("f")) || '';
- my $frag = html_quote($uri->fragment) || '';
- my $from_rev = html_quote($uri->query_param_delete("h")) || '';
- my $to_rev = html_quote($uri->query_param_delete("hb")) || '';
+ my $action = html_quote($uri->query_param_delete("a")) || '';
+ my $file = html_quote($uri->query_param_delete("f")) || '';
+ my $frag = html_quote($uri->fragment) || '';
+ my $from_rev = html_quote($uri->query_param_delete("h")) || '';
+ my $to_rev = html_quote($uri->query_param_delete("hb")) || '';
- if ($frag) {
- $frag =~ tr/l/L/;
- $frag = "#$frag";
- }
+ if ($frag) {
+ $frag =~ tr/l/L/;
+ $frag = "#$frag";
+ }
- $to_rev = $from_rev if !$to_rev;
- $to_rev = 'master' if $to_rev eq 'HEAD';
- $to_rev =~ s#refs/heads/(.*)$#$1#;
+ $to_rev = $from_rev if !$to_rev;
+ $to_rev = 'master' if $to_rev eq 'HEAD';
+ $to_rev =~ s#refs/heads/(.*)$#$1#;
- $repo = 'mozilla-bteam/bmo' if $repo =~ /^webtools\/bmo\/bugzilla\.git$/;
- $repo = 'bugzilla/bugzilla' if $repo =~ /^bugzilla\/bugzilla\.git$/;
- $repo = 'bugzilla/bugzilla.org' if $repo =~ /^www\/bugzilla\.org\.git$/;
+ $repo = 'mozilla-bteam/bmo' if $repo =~ /^webtools\/bmo\/bugzilla\.git$/;
+ $repo = 'bugzilla/bugzilla' if $repo =~ /^bugzilla\/bugzilla\.git$/;
+ $repo = 'bugzilla/bugzilla.org' if $repo =~ /^www\/bugzilla\.org\.git$/;
- if ($action eq 'tree') {
- return $to_rev eq 'HEAD'
- ? qq#<a href="https://github.com/$repo">$text [github]</a>#
- : qq#<a href="https://github.com/$repo/tree/$to_rev">$text [github]</a>#;
- }
- if ($action eq 'blob') {
- return qq#<a href="https://github.com/$repo/blob/$to_rev/$file$frag">$text [github]</a>#;
- }
- if ($action eq 'shortlog' || $action eq 'log') {
- return qq#<a href="https://github.com/$repo/commits/$to_rev">$text [github]</a>#;
- }
- if ($action eq 'commit' || $action eq 'commitdiff') {
- return qq#<a href="https://github.com/$repo/commit/$to_rev">$text [github]</a>#;
- }
- return qq#<a href="$text">$text</a>#;
+ if ($action eq 'tree') {
+ return $to_rev eq 'HEAD'
+ ? qq#<a href="https://github.com/$repo">$text [github]</a>#
+ : qq#<a href="https://github.com/$repo/tree/$to_rev">$text [github]</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>};
+ if ($action eq 'blob') {
+ return
+ qq#<a href="https://github.com/$repo/blob/$to_rev/$file$frag">$text [github]</a>#;
}
- });
+ if ($action eq 'shortlog' || $action eq 'log') {
+ return
+ qq#<a href="https://github.com/$repo/commits/$to_rev">$text [github]</a>#;
+ }
+ if ($action eq 'commit' || $action eq 'commitdiff') {
+ return qq#<a href="https://github.com/$repo/commit/$to_rev">$text [github]</a>#;
+ }
+ return qq#<a href="$text">$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'};
+ my ($self, $args) = @_;
+ my $map = $args->{'map'};
- foreach my $name (keys %$map) {
- if ($name =~ /cf_crash_signature$/) {
- $map->{'sig'} = $name;
- }
+ foreach my $name (keys %$map) {
+ if ($name =~ /cf_crash_signature$/) {
+ $map->{'sig'} = $name;
}
+ }
}
sub object_columns {
- my ($self, $args) = @_;
- return unless $args->{class}->isa('Bugzilla::Product');
- push @{ $args->{columns} }, qw(
- default_platform_id
- default_op_sys_id
- security_group_id
- );
+ my ($self, $args) = @_;
+ return unless $args->{class}->isa('Bugzilla::Product');
+ push @{$args->{columns}}, qw(
+ default_platform_id
+ default_op_sys_id
+ security_group_id
+ );
}
sub object_update_columns {
- my ($self, $args) = @_;
- return unless $args->{object}->isa('Bugzilla::Product');
- push @{ $args->{columns} }, qw(
- default_platform_id
- default_op_sys_id
- security_group_id
- );
+ my ($self, $args) = @_;
+ return unless $args->{object}->isa('Bugzilla::Product');
+ push @{$args->{columns}}, qw(
+ default_platform_id
+ default_op_sys_id
+ security_group_id
+ );
}
sub object_before_create {
- my ($self, $args) = @_;
- return unless $args->{class}->isa('Bugzilla::Product');
+ my ($self, $args) = @_;
+ return unless $args->{class}->isa('Bugzilla::Product');
- my $cgi = Bugzilla->cgi;
- my $params = $args->{params};
- foreach my $field (qw( default_platform_id default_op_sys_id security_group_id )) {
- $params->{$field} = $cgi->param($field);
- }
+ my $cgi = Bugzilla->cgi;
+ my $params = $args->{params};
+ foreach
+ my $field (qw( default_platform_id default_op_sys_id security_group_id ))
+ {
+ $params->{$field} = $cgi->param($field);
+ }
}
sub object_end_of_set_all {
- my ($self, $args) = @_;
- my $object = $args->{object};
- return unless $object->isa('Bugzilla::Product');
-
- my $cgi = Bugzilla->cgi;
- my $params = $args->{params};
- foreach my $field (qw( default_platform_id default_op_sys_id security_group_id )) {
- my $value = $cgi->param($field);
- detaint_natural($value);
- $object->set($field, $value);
- }
+ my ($self, $args) = @_;
+ my $object = $args->{object};
+ return unless $object->isa('Bugzilla::Product');
+
+ my $cgi = Bugzilla->cgi;
+ my $params = $args->{params};
+ foreach
+ my $field (qw( default_platform_id default_op_sys_id security_group_id ))
+ {
+ my $value = $cgi->param($field);
+ detaint_natural($value);
+ $object->set($field, $value);
+ }
}
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
- Bugzilla->audit(sprintf('<%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 => Bugzilla->params->{'nobody_user'} })
- 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
- );
- }
+ my ($self, $args) = @_;
+ my $class = $args->{class};
+
+ if ($class eq 'Bugzilla::User') {
+ my $user = $args->{object};
+
+ # Log real IP addresses for auditing
+ Bugzilla->audit(sprintf('<%s> created user %s', remote_ip(), $user->login));
+
+ # Add default searches to new user's footer
+ my $dbh = Bugzilla->dbh;
- } elsif ($class eq 'Bugzilla::Bug') {
- # Log real IP addresses for auditing
- Bugzilla->audit(sprintf('%s <%s> created bug %s', Bugzilla->user->login, remote_ip(), $args->{object}->id));
+ my $sharer = Bugzilla::User->new({name => Bugzilla->params->{'nobody_user'}})
+ 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
+ Bugzilla->audit(sprintf(
+ '%s <%s> created bug %s',
+ Bugzilla->user->login, remote_ip(), $args->{object}->id
+ ));
+ }
}
sub _bug_reporters_hw_os {
- my ($self) = @_;
- return $self->{ua_hw_os} if exists $self->{ua_hw_os};
- my $memcached = Bugzilla->memcached;
- my $hw_os = $memcached->get({ key => 'bug.ua.' . $self->id });
- if (!$hw_os) {
- (my $ua) = Bugzilla->dbh->selectrow_array(
- "SELECT user_agent FROM bug_user_agent WHERE bug_id = ?",
- undef,
- $self->id);
- $hw_os = $ua
- ? [ detect_platform($ua), detect_op_sys($ua) ]
- : [];
- $memcached->set({ key => 'bug.ua.' . $self->id, value => $hw_os });
- }
- return $self->{ua_hw_os} = $hw_os;
+ my ($self) = @_;
+ return $self->{ua_hw_os} if exists $self->{ua_hw_os};
+ my $memcached = Bugzilla->memcached;
+ my $hw_os = $memcached->get({key => 'bug.ua.' . $self->id});
+ if (!$hw_os) {
+ (my $ua)
+ = Bugzilla->dbh->selectrow_array(
+ "SELECT user_agent FROM bug_user_agent WHERE bug_id = ?",
+ undef, $self->id);
+ $hw_os = $ua ? [detect_platform($ua), detect_op_sys($ua)] : [];
+ $memcached->set({key => 'bug.ua.' . $self->id, value => $hw_os});
+ }
+ return $self->{ua_hw_os} = $hw_os;
}
sub _bug_is_unassigned {
- my ($self) = @_;
- my $assignee = $self->assigned_to->login;
- return $assignee eq Bugzilla->params->{'nobody_user'} || $assignee =~ /\.bugs$/;
+ my ($self) = @_;
+ my $assignee = $self->assigned_to->login;
+ return $assignee eq Bugzilla->params->{'nobody_user'} || $assignee =~ /\.bugs$/;
}
sub _bug_has_current_patch {
- my ($self) = @_;
- foreach my $attachment (@{ $self->attachments }) {
- next if $attachment->isobsolete;
- return 1 if $attachment->can_review;
- }
- return 0;
+ my ($self) = @_;
+ foreach my $attachment (@{$self->attachments}) {
+ next if $attachment->isobsolete;
+ return 1 if $attachment->can_review;
+ }
+ return 0;
}
sub _bug_missing_sec_approval {
- my ($self) = @_;
- # see https://wiki.mozilla.org/Security/Bug_Approval_Process for the rules
+ my ($self) = @_;
- # no need to alert once a bug is closed
- return 0 if $self->resolution;
+ # see https://wiki.mozilla.org/Security/Bug_Approval_Process for the rules
- # only bugs with sec-high or sec-critical keywords need sec-approval
- return 0 unless $self->has_keyword('sec-high') || $self->has_keyword('sec-critical');
+ # no need to alert once a bug is closed
+ return 0 if $self->resolution;
- # look for patches with sec-approval set to any value
- foreach my $attachment (@{ $self->attachments }) {
- next if $attachment->isobsolete || !$attachment->ispatch;
- foreach my $flag (@{ $attachment->flags }) {
- # only one patch needs sec-approval
- return 0 if $flag->name eq 'sec-approval';
- }
- }
+ # only bugs with sec-high or sec-critical keywords need sec-approval
+ return 0
+ unless $self->has_keyword('sec-high') || $self->has_keyword('sec-critical');
- # tracking flags
- require Bugzilla::Extension::TrackingFlags::Flag;
- my $flags = Bugzilla::Extension::TrackingFlags::Flag->match({
- product => $self->product,
- component => $self->component,
- bug_id => $self->id,
- is_active => 1,
- WHERE => {
- 'name like ?' => 'cf_status_firefox%',
- },
- });
- # set flags are added after the sql query, filter those out
- $flags = [ grep { $_->name =~ /^cf_status_firefox/ } @$flags ];
- return 0 unless @$flags;
-
- my $nightly = last_value { $_->name !~ /_esr\d+$/ } @$flags;
- my $set = 0;
- foreach my $flag (@$flags) {
- my $value = $flag->bug_flag($self->id)->value;
- next if $value eq '---';
- $set++;
- # sec-approval is required if any of the current status-firefox
- # tracking flags that aren't the latest are set to 'affected'
- return 1 if $flag->name ne $nightly->name && $value eq 'affected';
+ # look for patches with sec-approval set to any value
+ foreach my $attachment (@{$self->attachments}) {
+ next if $attachment->isobsolete || !$attachment->ispatch;
+ foreach my $flag (@{$attachment->flags}) {
+
+ # only one patch needs sec-approval
+ return 0 if $flag->name eq 'sec-approval';
}
- # sec-approval is required if no tracking flags are set
- return $set == 0;
+ }
+
+ # tracking flags
+ require Bugzilla::Extension::TrackingFlags::Flag;
+ my $flags = Bugzilla::Extension::TrackingFlags::Flag->match({
+ product => $self->product,
+ component => $self->component,
+ bug_id => $self->id,
+ is_active => 1,
+ WHERE => {'name like ?' => 'cf_status_firefox%',},
+ });
+
+ # set flags are added after the sql query, filter those out
+ $flags = [grep { $_->name =~ /^cf_status_firefox/ } @$flags];
+ return 0 unless @$flags;
+
+ my $nightly = last_value { $_->name !~ /_esr\d+$/ } @$flags;
+ my $set = 0;
+ foreach my $flag (@$flags) {
+ my $value = $flag->bug_flag($self->id)->value;
+ next if $value eq '---';
+ $set++;
+
+ # sec-approval is required if any of the current status-firefox
+ # tracking flags that aren't the latest are set to 'affected'
+ return 1 if $flag->name ne $nightly->name && $value eq 'affected';
+ }
+
+ # sec-approval is required if no tracking flags are set
+ return $set == 0;
}
sub _product_default_platform_id { $_[0]->{default_platform_id} }
-sub _product_default_op_sys_id { $_[0]->{default_op_sys_id} }
+sub _product_default_op_sys_id { $_[0]->{default_op_sys_id} }
sub _product_default_platform {
- my ($self) = @_;
- if (!exists $self->{default_platform}) {
- $self->{default_platform} = $self->default_platform_id
- ? Bugzilla::Field::Choice
- ->type('rep_platform')
- ->new($_[0]->{default_platform_id})
- ->name
- : undef;
- }
- return $self->{default_platform};
+ my ($self) = @_;
+ if (!exists $self->{default_platform}) {
+ $self->{default_platform}
+ = $self->default_platform_id
+ ? Bugzilla::Field::Choice->type('rep_platform')
+ ->new($_[0]->{default_platform_id})->name
+ : undef;
+ }
+ return $self->{default_platform};
}
+
sub _product_default_op_sys {
- my ($self) = @_;
- if (!exists $self->{default_op_sys}) {
- $self->{default_op_sys} = $self->default_op_sys_id
- ? Bugzilla::Field::Choice
- ->type('op_sys')
- ->new($_[0]->{default_op_sys_id})
- ->name
- : undef;
- }
- return $self->{default_op_sys};
+ my ($self) = @_;
+ if (!exists $self->{default_op_sys}) {
+ $self->{default_op_sys}
+ = $self->default_op_sys_id
+ ? Bugzilla::Field::Choice->type('op_sys')->new($_[0]->{default_op_sys_id})
+ ->name
+ : undef;
+ }
+ return $self->{default_op_sys};
}
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;
+ 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;
}
sub bug_end_of_create {
- my ($self, $args) = @_;
- my $bug = $args->{'bug'};
-
- # automatically CC users to bugs based on group & product
- 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);
- }
- }
- }
-
- # store user-agent
- if (my $ua = Bugzilla->cgi->user_agent) {
- trick_taint($ua);
- Bugzilla->dbh->do(
- "INSERT INTO bug_user_agent (bug_id, user_agent) VALUES (?, ?)",
- undef,
- $bug->id, $ua
- );
- }
+ my ($self, $args) = @_;
+ my $bug = $args->{'bug'};
+
+ # automatically CC users to bugs based on group & product
+ 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);
+ }
+ }
+ }
+
+ # store user-agent
+ if (my $ua = Bugzilla->cgi->user_agent) {
+ trick_taint($ua);
+ Bugzilla->dbh->do(
+ "INSERT INTO bug_user_agent (bug_id, user_agent) VALUES (?, ?)",
+ undef, $bug->id, $ua);
+ }
}
sub sanitycheck_check {
- my ($self, $args) = @_;
+ my ($self, $args) = @_;
- my $dbh = Bugzilla->dbh;
- my $status = $args->{'status'};
- $status->('bmo_check_cf_visible_in_products');
-
- my $products = $dbh->selectcol_arrayref('SELECT name FROM products');
- my %product = map { $_ => 1 } @$products;
- my @cf_products = map { keys %$_ } values %$cf_visible_in_products;
- foreach my $cf_product (@cf_products) {
- $status->('bmo_check_cf_visible_in_products_missing',
- { cf_product => $cf_product }, 'alert') unless $product{$cf_product};
- }
+ my $dbh = Bugzilla->dbh;
+ my $status = $args->{'status'};
+ $status->('bmo_check_cf_visible_in_products');
+
+ my $products = $dbh->selectcol_arrayref('SELECT name FROM products');
+ my %product = map { $_ => 1 } @$products;
+ my @cf_products = map { keys %$_ } values %$cf_visible_in_products;
+ foreach my $cf_product (@cf_products) {
+ $status->(
+ 'bmo_check_cf_visible_in_products_missing',
+ {cf_product => $cf_product}, 'alert'
+ ) unless $product{$cf_product};
+ }
}
sub db_sanitize {
- print "deleting reporter's user-agents...\n";
- Bugzilla->dbh->do("TRUNCATE TABLE bug_user_agent");
+ print "deleting reporter's user-agents...\n";
+ Bugzilla->dbh->do("TRUNCATE TABLE bug_user_agent");
}
# bugs in an ASSIGNED state must be assigned to a real person
# reset bugs to NEW if the assignee is nobody/.bugs$
sub object_start_of_update {
- my ($self, $args) = @_;
- my ($new_bug, $old_bug) = @$args{qw( object old_object )};
- return unless $new_bug->isa('Bugzilla::Bug');
-
- # if either the assignee or status has changed
- return unless
- $old_bug->assigned_to->id != $new_bug->assigned_to->id
- || $old_bug->bug_status ne $new_bug->bug_status;
-
- # and the bug is now ASSIGNED
- return unless
- $new_bug->bug_status eq 'ASSIGNED';
-
- # and the assignee isn't a real person
- return unless
- $new_bug->assigned_to->login eq Bugzilla->params->{'nobody_user'}
- || $new_bug->assigned_to->login =~ /\.bugs$/;
-
- # and the user can set the status to NEW
- return unless
- $old_bug->check_can_change_field('bug_status', $old_bug->bug_status, 'NEW');
-
- # if the user is changing the assignee, silently change the bug's status to new
- if ($old_bug->assigned_to->id != $new_bug->assigned_to->id) {
- $new_bug->set_bug_status('NEW');
- }
+ my ($self, $args) = @_;
+ my ($new_bug, $old_bug) = @$args{qw( object old_object )};
+ return unless $new_bug->isa('Bugzilla::Bug');
- # otherwise the user is trying to set the bug's status to ASSIGNED without
- # assigning a real person. throw an error.
- else {
- ThrowUserError('bug_status_unassigned');
- }
+ # if either the assignee or status has changed
+ return
+ unless $old_bug->assigned_to->id != $new_bug->assigned_to->id
+ || $old_bug->bug_status ne $new_bug->bug_status;
+
+ # and the bug is now ASSIGNED
+ return unless $new_bug->bug_status eq 'ASSIGNED';
+
+ # and the assignee isn't a real person
+ return
+ unless $new_bug->assigned_to->login eq Bugzilla->params->{'nobody_user'}
+ || $new_bug->assigned_to->login =~ /\.bugs$/;
+
+ # and the user can set the status to NEW
+ return
+ unless $old_bug->check_can_change_field('bug_status', $old_bug->bug_status,
+ 'NEW');
+
+ # if the user is changing the assignee, silently change the bug's status to new
+ if ($old_bug->assigned_to->id != $new_bug->assigned_to->id) {
+ $new_bug->set_bug_status('NEW');
+ }
+
+ # otherwise the user is trying to set the bug's status to ASSIGNED without
+ # assigning a real person. throw an error.
+ else {
+ ThrowUserError('bug_status_unassigned');
+ }
}
# 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 $detected = _detect_attached_url($url)) {
- $attributes->{mimetype} = $detected->{content_type};
- $attributes->{ispatch} = 0;
- }
+ 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 $detected = _detect_attached_url($url)) {
+ $attributes->{mimetype} = $detected->{content_type};
+ $attributes->{ispatch} = 0;
+ }
}
sub _detect_attached_url {
- my ($url) = @_;
-
- # trim and check for the pull request url
- return unless defined $url;
- return if length($url) > 256;
- $url = trim($url);
- # ignore urls that contain unescaped characters outside of the range mentioned in RFC 3986 section 2
- return if $url =~ m<[^A-Za-z0-9._~:/?#\[\]@!\$&'()*+,;=`.%-]>;
-
- foreach my $key (keys %autodetect_attach_urls) {
- my $regex = $autodetect_attach_urls{$key}->{regex};
- if (ref($regex) eq 'CODE') {
- $regex = $regex->();
- }
- if ($url =~ $regex) {
- return $autodetect_attach_urls{$key};
- }
+ my ($url) = @_;
+
+ # trim and check for the pull request url
+ return unless defined $url;
+ return if length($url) > 256;
+ $url = trim($url);
+
+# ignore urls that contain unescaped characters outside of the range mentioned in RFC 3986 section 2
+ return if $url =~ m<[^A-Za-z0-9._~:/?#\[\]@!\$&'()*+,;=`.%-]>;
+
+ foreach my $key (keys %autodetect_attach_urls) {
+ my $regex = $autodetect_attach_urls{$key}->{regex};
+ if (ref($regex) eq 'CODE') {
+ $regex = $regex->();
+ }
+ if ($url =~ $regex) {
+ return $autodetect_attach_urls{$key};
}
+ }
- return undef;
+ return undef;
}
sub _attachment_external_redirect {
- my ($self) = @_;
+ my ($self) = @_;
- # must be our supported content-type
- return undef unless
- any { $self->contenttype eq $autodetect_attach_urls{$_}->{content_type} }
- keys %autodetect_attach_urls;
+ # must be our supported content-type
+ return undef
+ unless
+ any { $self->contenttype eq $autodetect_attach_urls{$_}->{content_type} }
+ keys %autodetect_attach_urls;
- # must still be a valid url
- return _detect_attached_url($self->data)
+ # must still be a valid url
+ return _detect_attached_url($self->data);
}
sub _attachment_can_review {
- my ($self) = @_;
+ my ($self) = @_;
- return 1 if $self->ispatch;
- my $external = $self->external_redirect // return;
- return $external->{can_review};
+ return 1 if $self->ispatch;
+ my $external = $self->external_redirect // return;
+ return $external->{can_review};
}
sub _attachment_fetch_github_pr_diff {
- my ($self) = @_;
+ my ($self) = @_;
- # must be our supported content-type
- return undef unless
- any { $self->contenttype eq $autodetect_attach_urls{$_}->{content_type} }
- keys %autodetect_attach_urls;
+ # must be our supported content-type
+ return undef
+ unless
+ any { $self->contenttype eq $autodetect_attach_urls{$_}->{content_type} }
+ keys %autodetect_attach_urls;
- # must still be a valid url
- return undef unless _detect_attached_url($self->data);
+ # must still be a valid url
+ return undef unless _detect_attached_url($self->data);
- my $ua = LWP::UserAgent->new( timeout => 10 );
- if (Bugzilla->params->{proxy_url}) {
- $ua->proxy('https', Bugzilla->params->{proxy_url});
- }
+ my $ua = LWP::UserAgent->new(timeout => 10);
+ if (Bugzilla->params->{proxy_url}) {
+ $ua->proxy('https', Bugzilla->params->{proxy_url});
+ }
- my $pr_diff = $self->data . ".diff";
- my $response = $ua->get($pr_diff);
- if ($response->is_error) {
- warn "Github fetch error: $pr_diff, " . $response->status_line;
- return "Error retrieving Github pull request diff for " . $self->data;
- }
- return $response->decoded_content;
+ my $pr_diff = $self->data . ".diff";
+ my $response = $ua->get($pr_diff);
+ if ($response->is_error) {
+ warn "Github fetch error: $pr_diff, " . $response->status_line;
+ return "Error retrieving Github pull request diff for " . $self->data;
+ }
+ return $response->decoded_content;
}
# redirect automatically to github urls
sub attachment_view {
- my ($self, $args) = @_;
- my $attachment = $args->{attachment};
- my $cgi = Bugzilla->cgi;
+ 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');
+ # don't redirect if the content-type is specified explicitly
+ return if defined $cgi->param('content_type');
- # must be a valid redirection url
- return unless defined $attachment->external_redirect;
+ # must be a valid redirection url
+ return unless defined $attachment->external_redirect;
- # redirect
- print $cgi->redirect(trim($attachment->data));
- exit;
+ # redirect
+ print $cgi->redirect(trim($attachment->data));
+ exit;
}
sub install_before_final_checks {
- my ($self, $args) = @_;
-
- # Add product chooser setting
- add_setting({
- name => 'product_chooser',
- options => ['pretty_product_chooser', 'full_product_chooser'],
- default => 'pretty_product_chooser',
- category => 'User Interface'
- });
-
- # Add option to inject x-bugzilla headers into the message body to work
- # around gmail filtering limitations
- add_setting({
- name => 'headers_in_body',
- options => ['on', 'off'],
- default => 'off',
- category => 'Email Notifications'
- });
-
- # 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
+ my ($self, $args) = @_;
+
+ # Add product chooser setting
+ add_setting({
+ name => 'product_chooser',
+ options => ['pretty_product_chooser', 'full_product_chooser'],
+ default => 'pretty_product_chooser',
+ category => 'User Interface'
+ });
+
+ # Add option to inject x-bugzilla headers into the message body to work
+ # around gmail filtering limitations
+ add_setting({
+ name => 'headers_in_body',
+ options => ['on', 'off'],
+ default => 'off',
+ category => 'Email Notifications'
+ });
+
+ # 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
+ 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
+ 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
+ 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();
- }
+ WHERE setting_name='gmail_threading'"
+ );
+ $dbh->do("DELETE FROM setting WHERE name='gmail_threading'");
+ $dbh->bz_commit_transaction();
+ }
}
sub db_schema_abstract_schema {
- my ($self, $args) = @_;
- $args->{schema}->{bug_user_agent} = {
- FIELDS => [
- id => {
- TYPE => 'MEDIUMSERIAL',
- NOTNULL => 1,
- PRIMARYKEY => 1,
- },
- bug_id => {
- TYPE => 'INT3',
- NOTNULL => 1,
- REFERENCES => {
- TABLE => 'bugs',
- COLUMN => 'bug_id',
- DELETE => 'CASCADE',
- },
- },
- user_agent => {
- TYPE => 'MEDIUMTEXT',
- NOTNULL => 1,
- },
- ],
- INDEXES => [
- bug_user_agent_idx => {
- FIELDS => [ 'bug_id' ],
- TYPE => 'UNIQUE',
- },
- ],
- };
- $args->{schema}->{job_last_run} = {
- FIELDS => [
- id => {
- TYPE => 'INTSERIAL',
- NOTNULL => 1,
- PRIMARYKEY => 1,
- },
- name => {
- TYPE => 'VARCHAR(100)',
- NOTNULL => 1,
- },
- last_run => {
- TYPE => 'DATETIME',
- NOTNULL => 1,
- },
- ],
- INDEXES => [
- job_last_run_name_idx => {
- FIELDS => [ 'name' ],
- TYPE => 'UNIQUE',
- },
- ],
- };
- $args->{schema}->{secbugs_BugHistory} = {
- FIELDS => [
- bugid => { TYPE => 'BIGINT', NOTNULL => 1 },
- changetime => { TYPE => 'NATIVE_DATETIME' },
- fieldname => { TYPE => 'VARCHAR(32)', NOTNULL => 1 },
- new => { TYPE => 'VARCHAR(255)' },
- old => { TYPE => 'VARCHAR(255)' },
- ],
- };
-
- $args->{schema}->{secbugs_Bugs} = {
- FIELDS => [
- bugid => { TYPE => 'BIGINT', NOTNULL => 1, PRIMARYKEY => 1 },
- opendate => { TYPE => 'NATIVE_DATETIME' },
- closedate => { TYPE => 'NATIVE_DATETIME', NOTNULL => 1 },
- severity => { TYPE => 'VARCHAR(16)' },
- summary => { TYPE => 'VARCHAR(255)' },
- updated => { TYPE => 'NATIVE_DATETIME' },
- ],
- };
-
- $args->{schema}->{secbugs_Details} = {
- FIELDS => [
- did => {
- TYPE => 'INTSERIAL',
- NOTNULL => 1,
- PRIMARYKEY => 1,
- },
- sid => {
- TYPE => 'INT4',
- },
- product => {
- TYPE => 'VARCHAR(255)',
- },
- component => {
- TYPE => 'VARCHAR(255)',
- },
- count => { TYPE => 'INT4' },
- bug_list => { TYPE => 'TEXT' },
- date => { TYPE => 'NATIVE_DATETIME' },
- avg_age_days => { TYPE => 'INT4' },
- med_age_days => { TYPE => 'INT4' },
- ]
- };
-
- $args->{schema}->{secbugs_Stats} = {
- FIELDS => [
- sid => { TYPE => 'INTSERIAL', NOTNULL => 1, PRIMARYKEY => 1 },
- category => { TYPE => 'VARCHAR(32)' },
- count => { TYPE => 'INT4' },
- date => { TYPE => 'NATIVE_DATETIME' },
- ]
- };
+ my ($self, $args) = @_;
+ $args->{schema}->{bug_user_agent} = {
+ FIELDS => [
+ id => {TYPE => 'MEDIUMSERIAL', NOTNULL => 1, PRIMARYKEY => 1,},
+ bug_id => {
+ TYPE => 'INT3',
+ NOTNULL => 1,
+ REFERENCES => {TABLE => 'bugs', COLUMN => 'bug_id', DELETE => 'CASCADE',},
+ },
+ user_agent => {TYPE => 'MEDIUMTEXT', NOTNULL => 1,},
+ ],
+ INDEXES => [bug_user_agent_idx => {FIELDS => ['bug_id'], TYPE => 'UNIQUE',},],
+ };
+ $args->{schema}->{job_last_run} = {
+ FIELDS => [
+ id => {TYPE => 'INTSERIAL', NOTNULL => 1, PRIMARYKEY => 1,},
+ name => {TYPE => 'VARCHAR(100)', NOTNULL => 1,},
+ last_run => {TYPE => 'DATETIME', NOTNULL => 1,},
+ ],
+ INDEXES => [job_last_run_name_idx => {FIELDS => ['name'], TYPE => 'UNIQUE',},],
+ };
+ $args->{schema}->{secbugs_BugHistory} = {
+ FIELDS => [
+ bugid => {TYPE => 'BIGINT', NOTNULL => 1},
+ changetime => {TYPE => 'NATIVE_DATETIME'},
+ fieldname => {TYPE => 'VARCHAR(32)', NOTNULL => 1},
+ new => {TYPE => 'VARCHAR(255)'},
+ old => {TYPE => 'VARCHAR(255)'},
+ ],
+ };
+
+ $args->{schema}->{secbugs_Bugs} = {
+ FIELDS => [
+ bugid => {TYPE => 'BIGINT', NOTNULL => 1, PRIMARYKEY => 1},
+ opendate => {TYPE => 'NATIVE_DATETIME'},
+ closedate => {TYPE => 'NATIVE_DATETIME', NOTNULL => 1},
+ severity => {TYPE => 'VARCHAR(16)'},
+ summary => {TYPE => 'VARCHAR(255)'},
+ updated => {TYPE => 'NATIVE_DATETIME'},
+ ],
+ };
+
+ $args->{schema}->{secbugs_Details} = {
+ FIELDS => [
+ did => {TYPE => 'INTSERIAL', NOTNULL => 1, PRIMARYKEY => 1,},
+ sid => {TYPE => 'INT4',},
+ product => {TYPE => 'VARCHAR(255)',},
+ component => {TYPE => 'VARCHAR(255)',},
+ count => {TYPE => 'INT4'},
+ bug_list => {TYPE => 'TEXT'},
+ date => {TYPE => 'NATIVE_DATETIME'},
+ avg_age_days => {TYPE => 'INT4'},
+ med_age_days => {TYPE => 'INT4'},
+ ]
+ };
+
+ $args->{schema}->{secbugs_Stats} = {
+ FIELDS => [
+ sid => {TYPE => 'INTSERIAL', NOTNULL => 1, PRIMARYKEY => 1},
+ category => {TYPE => 'VARCHAR(32)'},
+ count => {TYPE => 'INT4'},
+ date => {TYPE => 'NATIVE_DATETIME'},
+ ]
+ };
}
sub install_update_db {
- my $dbh = Bugzilla->dbh;
+ my $dbh = Bugzilla->dbh;
+
+ # per-product hw/os defaults
+ my $op_sys_default = _field_value('op_sys', 'Unspecified', 50);
+ $dbh->bz_add_column(
+ 'products',
+ 'default_op_sys_id' => {
+ TYPE => 'INT2',
+ DEFAULT => $op_sys_default->id,
+ REFERENCES => {TABLE => 'op_sys', COLUMN => 'id', DELETE => 'SET NULL',},
+ }
+ );
+ my $platform_default = _field_value('rep_platform', 'Unspecified', 50);
+ $dbh->bz_add_column(
+ 'products',
+ 'default_platform_id' => {
+ TYPE => 'INT2',
+ DEFAULT => $platform_default->id,
+ REFERENCES => {TABLE => 'rep_platform', COLUMN => 'id', DELETE => 'SET NULL',},
+ }
+ );
+
+ # 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).
+ 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');
+ }
+
+ # remove tables from the old TryAutoLand extension
+ $dbh->bz_drop_table('autoland_branches');
+ $dbh->bz_drop_table('autoland_attachments');
+
+ unless (Bugzilla::Field->new({name => 'cf_rank'})) {
+ Bugzilla::Field->create({
+ name => 'cf_rank',
+ description => 'Rank',
+ type => FIELD_TYPE_INTEGER,
+ mailhead => 0,
+ enter_bug => 0,
+ obsolete => 0,
+ custom => 1,
+ buglist => 1,
+ });
+ }
+ unless (Bugzilla::Field->new({name => 'cf_crash_signature'})) {
+ Bugzilla::Field->create({
+ name => 'cf_crash_signature',
+ description => 'Crash Signature',
+ type => FIELD_TYPE_TEXTAREA,
+ mailhead => 0,
+ enter_bug => 1,
+ obsolete => 0,
+ custom => 1,
+ buglist => 0,
+ });
+ }
- # per-product hw/os defaults
- my $op_sys_default = _field_value('op_sys', 'Unspecified', 50);
- $dbh->bz_add_column(
- 'products',
- 'default_op_sys_id' => {
- TYPE => 'INT2',
- DEFAULT => $op_sys_default->id,
- REFERENCES => {
- TABLE => 'op_sys',
- COLUMN => 'id',
- DELETE => 'SET NULL',
- },
- }
- );
- my $platform_default = _field_value('rep_platform', 'Unspecified', 50);
+ # Add default security group id column
+ if (!$dbh->bz_column_info('products', 'security_group_id')) {
$dbh->bz_add_column(
- 'products',
- 'default_platform_id' => {
- TYPE => 'INT2',
- DEFAULT => $platform_default->id,
- REFERENCES => {
- TABLE => 'rep_platform',
- COLUMN => 'id',
- DELETE => 'SET NULL',
- },
- }
+ 'products',
+ 'security_group_id' => {
+ TYPE => 'INT3',
+ REFERENCES => {TABLE => 'groups', COLUMN => 'id', DELETE => 'SET NULL',},
+ }
);
- # 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).
- 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');
- }
-
- # remove tables from the old TryAutoLand extension
- $dbh->bz_drop_table('autoland_branches');
- $dbh->bz_drop_table('autoland_attachments');
-
- unless (Bugzilla::Field->new({ name => 'cf_rank' })) {
- Bugzilla::Field->create({
- name => 'cf_rank',
- description => 'Rank',
- type => FIELD_TYPE_INTEGER,
- mailhead => 0,
- enter_bug => 0,
- obsolete => 0,
- custom => 1,
- buglist => 1,
- });
- }
- unless (Bugzilla::Field->new({ name => 'cf_crash_signature' })) {
- Bugzilla::Field->create({
- name => 'cf_crash_signature',
- description => 'Crash Signature',
- type => FIELD_TYPE_TEXTAREA,
- mailhead => 0,
- enter_bug => 1,
- obsolete => 0,
- custom => 1,
- buglist => 0,
- });
- }
-
- # Add default security group id column
- if (!$dbh->bz_column_info('products', 'security_group_id')) {
- $dbh->bz_add_column(
- 'products',
- 'security_group_id' => {
- TYPE => 'INT3',
- REFERENCES => {
- TABLE => 'groups',
- COLUMN => 'id',
- DELETE => 'SET NULL',
- },
- }
- );
-
- # if there are no groups, then we're creating a database from scratch
- # and there's nothing to migrate
- my ($group_count) = $dbh->selectrow_array("SELECT COUNT(*) FROM groups");
- if ($group_count) {
- # Migrate old product_sec_group mappings from the time this change was made
- my %product_sec_groups = (
- "addons.mozilla.org" => 'client-services-security',
- "Air Mozilla" => 'mozilla-employee-confidential',
- "Android Background Services" => 'cloud-services-security',
- "Audio/Visual Infrastructure" => 'mozilla-employee-confidential',
- "AUS" => 'client-services-security',
- "Bugzilla" => 'bugzilla-security',
- "bugzilla.mozilla.org" => 'bugzilla-security',
- "Cloud Services" => 'cloud-services-security',
- "Community Tools" => 'websites-security',
- "Data & BI Services Team" => 'metrics-private',
- "Developer Documentation" => 'websites-security',
- "Developer Ecosystem" => 'client-services-security',
- "Finance" => 'finance',
- "Firefox Friends" => 'mozilla-employee-confidential',
- "Firefox Health Report" => 'cloud-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 Foundation Operations" => 'mozilla-foundation-operations',
- "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',
- "Popcorn" => 'websites-security',
- "Privacy" => 'privacy',
- "quality.mozilla.org" => 'websites-security',
- "Recruiting" => 'hr',
- "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',
- "Taskcluster" => 'taskcluster-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',
- );
- # 1. Set all to core-security by default
- my $core_sec_group = Bugzilla::Group->new({ name => Bugzilla->params->{insidergroup} });
- $dbh->do("UPDATE products SET security_group_id = ?", undef, $core_sec_group->id);
- # 2. Update the ones that have explicit security groups
- foreach my $prod_name (keys %product_sec_groups) {
- my $group_name = $product_sec_groups{$prod_name};
- next if $group_name eq Bugzilla->params->{insidergroup}; # already done
- my $group = Bugzilla::Group->new({ name => $group_name, cache => 1 });
- if (!$group) {
- warn "Security group $group_name not found. Using insider group instead.\n";
- next;
- }
- $dbh->do("UPDATE products SET security_group_id = ? WHERE name = ?", undef, $group->id, $prod_name);
- }
+ # if there are no groups, then we're creating a database from scratch
+ # and there's nothing to migrate
+ my ($group_count) = $dbh->selectrow_array("SELECT COUNT(*) FROM groups");
+ if ($group_count) {
+
+ # Migrate old product_sec_group mappings from the time this change was made
+ my %product_sec_groups = (
+ "addons.mozilla.org" => 'client-services-security',
+ "Air Mozilla" => 'mozilla-employee-confidential',
+ "Android Background Services" => 'cloud-services-security',
+ "Audio/Visual Infrastructure" => 'mozilla-employee-confidential',
+ "AUS" => 'client-services-security',
+ "Bugzilla" => 'bugzilla-security',
+ "bugzilla.mozilla.org" => 'bugzilla-security',
+ "Cloud Services" => 'cloud-services-security',
+ "Community Tools" => 'websites-security',
+ "Data & BI Services Team" => 'metrics-private',
+ "Developer Documentation" => 'websites-security',
+ "Developer Ecosystem" => 'client-services-security',
+ "Finance" => 'finance',
+ "Firefox Friends" => 'mozilla-employee-confidential',
+ "Firefox Health Report" => 'cloud-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 Foundation Operations" => 'mozilla-foundation-operations',
+ "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',
+ "Popcorn" => 'websites-security',
+ "Privacy" => 'privacy',
+ "quality.mozilla.org" => 'websites-security',
+ "Recruiting" => 'hr',
+ "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',
+ "Taskcluster" => 'taskcluster-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',
+ );
+
+ # 1. Set all to core-security by default
+ my $core_sec_group
+ = Bugzilla::Group->new({name => Bugzilla->params->{insidergroup}});
+ $dbh->do("UPDATE products SET security_group_id = ?",
+ undef, $core_sec_group->id);
+
+ # 2. Update the ones that have explicit security groups
+ foreach my $prod_name (keys %product_sec_groups) {
+ my $group_name = $product_sec_groups{$prod_name};
+ next if $group_name eq Bugzilla->params->{insidergroup}; # already done
+ my $group = Bugzilla::Group->new({name => $group_name, cache => 1});
+ if (!$group) {
+ warn "Security group $group_name not found. Using insider group instead.\n";
+ next;
}
+ $dbh->do("UPDATE products SET security_group_id = ? WHERE name = ?",
+ undef, $group->id, $prod_name);
+ }
}
+ }
}
# return the Bugzilla::Field::Choice object for the specified field and value.
# if the value doesn't exist it will be created.
sub _field_value {
- my ($field_name, $value_name, $sort_key) = @_;
- my $field = Bugzilla::Field->check({ name => $field_name });
- my $existing = Bugzilla::Field::Choice->type($field)->match({ value => $value_name });
- return $existing->[0] if $existing && @$existing;
- return Bugzilla::Field::Choice->type($field)->create({
- value => $value_name,
- sortkey => $sort_key,
- isactive => 1,
- });
+ my ($field_name, $value_name, $sort_key) = @_;
+ my $field = Bugzilla::Field->check({name => $field_name});
+ my $existing
+ = Bugzilla::Field::Choice->type($field)->match({value => $value_name});
+ return $existing->[0] if $existing && @$existing;
+ return Bugzilla::Field::Choice->type($field)
+ ->create({value => $value_name, sortkey => $sort_key, isactive => 1,});
}
sub _last_closed_date {
- my ($self) = @_;
- my $dbh = Bugzilla->dbh;
+ my ($self) = @_;
+ my $dbh = Bugzilla->dbh;
- return $self->{'last_closed_date'} if defined $self->{'last_closed_date'};
+ 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');
+ 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("
+ $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
- );
+ ORDER BY bugs_activity.bug_when DESC " . $dbh->sql_limit(1), undef,
+ $status_field_id, $self->id);
- return $self->{'last_closed_date'};
+ 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->localconfig->{'urlbase'} ne 'https://bugzilla.mozilla.org/'
- && Bugzilla->localconfig->{'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 => Bugzilla->params->{'nobody_user'} }));
- print "Creating IT permission grant bug for new field '$name'...";
- }
-
- my $bug_data = {
- short_desc => "Custom field '$name' added to bugzilla.mozilla.org",
- product => 'Data & BI Services Team',
- component => 'Database Operations',
- bug_severity => 'normal',
- op_sys => 'All',
- rep_platform => 'All',
- version => 'other',
- };
-
- my $comment = <<COMMENT;
+ 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->localconfig->{'urlbase'} ne 'https://bugzilla.mozilla.org/'
+ && Bugzilla->localconfig->{'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 => Bugzilla->params->{'nobody_user'}}));
+ print "Creating IT permission grant bug for new field '$name'...";
+ }
+
+ my $bug_data = {
+ short_desc => "Custom field '$name' added to bugzilla.mozilla.org",
+ product => 'Data & BI Services Team',
+ component => 'Database Operations',
+ 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;
+ 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;
+ }
+ 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;
+ }
+ 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;
+ $bug_data->{'comment'} = $comment;
- my $old_error_mode = Bugzilla->error_mode;
- Bugzilla->error_mode(ERROR_MODE_DIE);
+ my $old_error_mode = Bugzilla->error_mode;
+ Bugzilla->error_mode(ERROR_MODE_DIE);
- my $new_bug = eval { Bugzilla::Bug->create($bug_data) };
+ my $new_bug = eval { Bugzilla::Bug->create($bug_data) };
- my $error = $@;
- undef $@;
- Bugzilla->error_mode($old_error_mode);
+ 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";
- }
+ 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";
- }
+ }
+ 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 ($self, $args) = @_;
- my $dispatch = $args->{dispatch};
- $dispatch->{BMO} = "Bugzilla::Extension::BMO::WebService";
+ my $dispatch = $args->{dispatch};
+ $dispatch->{BMO} = "Bugzilla::Extension::BMO::WebService";
}
sub psgi_builder {
- my ($self, $args) = @_;
- my $mount = $args->{mount};
-
- my $ses_index = Plack::Builder::builder(sub {
- my $auth_user = Bugzilla->localconfig->{ses_username};
- my $auth_pass = Bugzilla->localconfig->{ses_password};
- Plack::Builder::enable("Auth::Basic", authenticator => sub {
- my ($username, $password, $env) = @_;
- return ( $auth_user
- && $auth_pass
- && $username
- && $password
- && $username eq $auth_user
- && $password eq $auth_pass );
- });
- compile_cgi("ses/index.cgi");
- });
+ my ($self, $args) = @_;
+ my $mount = $args->{mount};
+
+ my $ses_index = Plack::Builder::builder(sub {
+ my $auth_user = Bugzilla->localconfig->{ses_username};
+ my $auth_pass = Bugzilla->localconfig->{ses_password};
+ Plack::Builder::enable(
+ "Auth::Basic",
+ authenticator => sub {
+ my ($username, $password, $env) = @_;
+ return ($auth_user
+ && $auth_pass
+ && $username
+ && $password
+ && $username eq $auth_user
+ && $password eq $auth_pass);
+ }
+ );
+ compile_cgi("ses/index.cgi");
+ });
- $mount->{'ses/index.cgi'} = $ses_index;
+ $mount->{'ses/index.cgi'} = $ses_index;
}
our $search_content_matches;
+
BEGIN {
- $search_content_matches = \&Bugzilla::Search::_content_matches;
+ $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;
- }
+ 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;
+ # copy of Bugzilla::Search::_content_matches with comment searching removed
- # 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 });
+ my ($self, $args) = @_;
+ my ($chart_id, $joins, $fields, $operator, $value)
+ = @$args{qw(chart_id joins fields operator value)};
+ my $dbh = Bugzilla->dbh;
- # 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;
+ # 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});
- # The term to use in the WHERE clause.
- if ($operator =~ /not/i) {
- $term = "NOT($term)";
- }
- $args->{term} = $term;
+ # 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 + " : '';
- 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;
+ # 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};
+ my ($self, $args) = @_;
+ my $email = $args->{email};
- _log_sent_email($email);
+ _log_sent_email($email);
- # $bug->mentors is added by the Review extension
- if (Bugzilla::Bug->can('mentors')) {
- _add_mentors_header($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);
+ # 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 $email = shift;
- my $recipient = $email->header('to');
- return unless $recipient;
+ my $recipient = $email->header('to');
+ return unless $recipient;
- my $subject = $email->header('Subject');
+ 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 || '?';
+ 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" : '-';
- $subject =~ s/[\[\(]Bug \d+[\]\)]\s*//;
+ 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 || '?';
- _syslog("[bugmail] $recipient ($message_type) $bug_id $subject");
+ $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));
+ 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;
- }
- }
- }
+ 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;
}
- else {
- push @headers, "$name: $value";
+ if (substr($value, 0, length($field) + 1) eq $field . ' ') {
+ push @headers, "$name: $field";
+ $value = substr($value, length($field) + 1);
+ last;
}
+ }
}
- $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);
- });
+ }
+ 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 ]);
- }
- elsif (!$email->content_type
- || $email->content_type =~ /^text\/(?:html|plain)/)
- {
- # text-only email
- _replace_placeholder_in_part($email, $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]);
+ }
+ elsif (!$email->content_type || $email->content_type =~ /^text\/(?:html|plain)/)
+ {
+ # text-only email
+ _replace_placeholder_in_part($email, $replacement);
+ }
}
sub _replace_placeholder_in_part {
- my ($part, $replacement) = @_;
+ my ($part, $replacement) = @_;
- _fix_encoding($part);
+ _fix_encoding($part);
- # replace
- my $placeholder = quotemeta('@@body-headers@@');
- my $body = $part->body_str;
- $body =~ s/$placeholder/$replacement/;
- $part->body_str_set($body);
+ # replace
+ my $placeholder = quotemeta('@@body-headers@@');
+ my $body = $part->body_str;
+ $body =~ s/$placeholder/$replacement/;
+ $part->body_str_set($body);
}
sub _fix_encoding {
- my $part = shift;
-
- # don't touch the top-level part of multi-part mail
- return if $part->parts > 1;
-
- # nothing to do if the part already has a charset
- my $ct = parse_content_type($part->content_type);
- my $charset = $ct->{attributes}{charset}
- ? $ct->{attributes}{charset}
- : '';
- return unless !$charset || $charset eq 'us-ascii';
-
- 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);
- }
+ my $part = shift;
+
+ # don't touch the top-level part of multi-part mail
+ return if $part->parts > 1;
+
+ # nothing to do if the part already has a charset
+ my $ct = parse_content_type($part->content_type);
+ my $charset = $ct->{attributes}{charset} ? $ct->{attributes}{charset} : '';
+ return unless !$charset || $charset eq 'us-ascii';
+
+ 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');
+ }
+ $part->encoding_set('quoted-printable');
}
sub _syslog {
- my $message = shift;
- openlog('apache', 'cons,pid', 'local4');
- syslog('notice', encode_utf8($message));
- closelog();
+ 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);
- }
- elsif ($format eq 'dev-engagement-event') {
- $self->_post_dev_engagement($args);
- }
- elsif ($format eq 'shield-studies') {
- $self->_post_shield_studies($args);
- }
+ 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);
+ }
+ elsif ($format eq 'dev-engagement-event') {
+ $self->_post_dev_engagement($args);
+ }
+ elsif ($format eq 'shield-studies') {
+ $self->_post_shield_studies($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 ($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 => Bugzilla->params->{'nobody_user'}}));
+ 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 ($investigate_bug, $ssh_key_bug);
- my $old_user = Bugzilla->user;
- eval {
- Bugzilla->set_user(Bugzilla::User->new({ name => Bugzilla->params->{'nobody_user'} }));
- 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 = $@;
+ 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);
- Bugzilla->error_mode($error_mode_cache);
+ $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 = $@;
- if ($error || !$investigate_bug || !$ssh_key_bug) {
- warn "Failed to create additional employee-incident bug: $error" if $error;
- $vars->{'message'} = 'employee_incident_creation_failed';
- }
+ 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 ];
+ 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);
+ # 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);
+ $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);
+ 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 _post_dev_engagement {
- my ($self, $args) = @_;
- my $vars = $args->{vars};
- my $parent_bug = $vars->{bug};
- my $template = Bugzilla->template;
- my $cgi = Bugzilla->cgi;
- my $params = Bugzilla->input_params;
- my $old_user = Bugzilla->user;
-
- my $error_mode_cache = Bugzilla->error_mode;
- Bugzilla->error_mode(ERROR_MODE_DIE);
-
- eval {
- # Add attachment containing tab delimited field values for
- # spreadsheet import.
- my @columns = qw(event start_date end_date location attendees
- audience desc mozilla_attending_list);
- my @attach_values;
- foreach my $column(@columns) {
- my $value = $params->{$column} || "";
- $value =~ s/"/""/g;
- push(@attach_values, qq{"$value"});
- }
-
- my @requested;
- foreach my $param (grep(/^request_/, keys %$params)) {
- next if !$params->{$param} || $param eq 'request_other_text';
- $param =~ s/^request_//;
- push(@requested, ucfirst($param));
- }
- push(@attach_values, '"' . join(",", @requested) . '"');
-
- # we wrap the data inside a textarea to allow for the delimited data to
- # be pasted directly into google docs.
-
- my $values = html_quote(join("\t", @attach_values));
- my $data = <<EOF;
+ my ($self, $args) = @_;
+ my $vars = $args->{vars};
+ my $parent_bug = $vars->{bug};
+ my $template = Bugzilla->template;
+ my $cgi = Bugzilla->cgi;
+ my $params = Bugzilla->input_params;
+ my $old_user = Bugzilla->user;
+
+ my $error_mode_cache = Bugzilla->error_mode;
+ Bugzilla->error_mode(ERROR_MODE_DIE);
+
+ eval {
+ # Add attachment containing tab delimited field values for
+ # spreadsheet import.
+ my @columns = qw(event start_date end_date location attendees
+ audience desc mozilla_attending_list);
+ my @attach_values;
+ foreach my $column (@columns) {
+ my $value = $params->{$column} || "";
+ $value =~ s/"/""/g;
+ push(@attach_values, qq{"$value"});
+ }
+
+ my @requested;
+ foreach my $param (grep(/^request_/, keys %$params)) {
+ next if !$params->{$param} || $param eq 'request_other_text';
+ $param =~ s/^request_//;
+ push(@requested, ucfirst($param));
+ }
+ push(@attach_values, '"' . join(",", @requested) . '"');
+
+ # we wrap the data inside a textarea to allow for the delimited data to
+ # be pasted directly into google docs.
+
+ my $values = html_quote(join("\t", @attach_values));
+ my $data = <<EOF;
<!doctype html>
<html>
<head>
@@ -2196,651 +2235,728 @@ sub _post_dev_engagement {
</html>
EOF
- $self->_add_attachment($args, {
- data => $data,
- description => 'Spreadsheet Data',
- filename => 'dev_engagement_submission.html',
- mimetype => 'text/html',
- });
- };
+ $self->_add_attachment(
+ $args,
+ {
+ data => $data,
+ description => 'Spreadsheet Data',
+ filename => 'dev_engagement_submission.html',
+ mimetype => 'text/html',
+ }
+ );
+ };
- $parent_bug->update($parent_bug->creation_ts);
+ $parent_bug->update($parent_bug->creation_ts);
}
sub _post_shield_studies {
- my ($self, $args) = @_;
- my $vars = $args->{vars};
- my $parent_bug = $vars->{bug};
- my $params = Bugzilla->input_params;
- my (@dep_comment, @dep_errors, @send_mail);
-
- # Common parameters always passed to _file_child_bug
- # bug_data and template_suffix will be different for each bug
- my $child_params = {
- parent_bug => $parent_bug,
- template_vars => $vars,
- dep_comment => \@dep_comment,
- dep_errors => \@dep_errors,
- send_mail => \@send_mail,
- };
-
- # Study Validation Review
- $child_params->{'bug_data'} = {
- short_desc => '[SHIELD] Study Validation Review for ' . $params->{hypothesis},
- product => 'Shield',
- component => 'Shield Study',
- bug_severity => 'normal',
- op_sys => 'All',
- rep_platform => 'All',
- version => 'unspecified',
- blocked => $parent_bug->bug_id,
- };
- $child_params->{'template_suffix'} = 'validation-review';
- _file_child_bug($child_params);
-
- # Shipping Status
- $child_params->{'bug_data'} = {
- short_desc => '[SHIELD] Shipping Status for ' . $params->{hypothesis},
- product => 'Shield',
- component => 'Shield Study',
- bug_severity => 'normal',
- op_sys => 'All',
- rep_platform => 'All',
- version => 'unspecified',
- blocked => $parent_bug->bug_id,
- };
- $child_params->{'template_suffix'} = 'shipping-status';
-
- # Data Review
- _file_child_bug($child_params);
- $child_params->{'bug_data'} = {
- short_desc => '[SHIELD] Data Review for ' . $params->{hypothesis},
- product => 'Shield',
- component => 'Shield Study',
- bug_severity => 'normal',
- op_sys => 'All',
- rep_platform => 'All',
- version => 'unspecified',
- blocked => $parent_bug->bug_id,
- };
- $child_params->{'template_suffix'} = 'data-review';
- _file_child_bug($child_params);
-
- # Legal Review
- $child_params->{'bug_data'} = {
- short_desc => '[SHIELD] Legal Review for ' . $params->{hypothesis},
- product => 'Legal',
- component => 'Firefox',
- bug_severity => 'normal',
- op_sys => 'All',
- rep_platform => 'All',
- groups => [ 'mozilla-employee-confidential' ],
- version => 'unspecified',
- blocked => $parent_bug->bug_id,
- };
- $child_params->{'template_suffix'} = 'legal';
- _file_child_bug($child_params);
-
+ my ($self, $args) = @_;
+ my $vars = $args->{vars};
+ my $parent_bug = $vars->{bug};
+ my $params = Bugzilla->input_params;
+ my (@dep_comment, @dep_errors, @send_mail);
+
+ # Common parameters always passed to _file_child_bug
+ # bug_data and template_suffix will be different for each bug
+ my $child_params = {
+ parent_bug => $parent_bug,
+ template_vars => $vars,
+ dep_comment => \@dep_comment,
+ dep_errors => \@dep_errors,
+ send_mail => \@send_mail,
+ };
+
+ # Study Validation Review
+ $child_params->{'bug_data'} = {
+ short_desc => '[SHIELD] Study Validation Review for ' . $params->{hypothesis},
+ product => 'Shield',
+ component => 'Shield Study',
+ bug_severity => 'normal',
+ op_sys => 'All',
+ rep_platform => 'All',
+ version => 'unspecified',
+ blocked => $parent_bug->bug_id,
+ };
+ $child_params->{'template_suffix'} = 'validation-review';
+ _file_child_bug($child_params);
+
+ # Shipping Status
+ $child_params->{'bug_data'} = {
+ short_desc => '[SHIELD] Shipping Status for ' . $params->{hypothesis},
+ product => 'Shield',
+ component => 'Shield Study',
+ bug_severity => 'normal',
+ op_sys => 'All',
+ rep_platform => 'All',
+ version => 'unspecified',
+ blocked => $parent_bug->bug_id,
+ };
+ $child_params->{'template_suffix'} = 'shipping-status';
+
+ # Data Review
+ _file_child_bug($child_params);
+ $child_params->{'bug_data'} = {
+ short_desc => '[SHIELD] Data Review for ' . $params->{hypothesis},
+ product => 'Shield',
+ component => 'Shield Study',
+ bug_severity => 'normal',
+ op_sys => 'All',
+ rep_platform => 'All',
+ version => 'unspecified',
+ blocked => $parent_bug->bug_id,
+ };
+ $child_params->{'template_suffix'} = 'data-review';
+ _file_child_bug($child_params);
+
+ # Legal Review
+ $child_params->{'bug_data'} = {
+ short_desc => '[SHIELD] Legal Review for ' . $params->{hypothesis},
+ product => 'Legal',
+ component => 'Firefox',
+ bug_severity => 'normal',
+ op_sys => 'All',
+ rep_platform => 'All',
+ groups => ['mozilla-employee-confidential'],
+ version => 'unspecified',
+ blocked => $parent_bug->bug_id,
+ };
+ $child_params->{'template_suffix'} = 'legal';
+ _file_child_bug($child_params);
+
+ if (scalar @dep_errors) {
+ warn "[Bug "
+ . $parent_bug->id
+ . "] Failed to create additional moz-project-review bugs:\n"
+ . join("\n", @dep_errors);
+ $vars->{'message'} = 'moz_project_review_creation_failed';
+ }
+
+ if (scalar @dep_comment) {
+ my $comment = join("\n", @dep_comment);
if (scalar @dep_errors) {
- warn "[Bug " . $parent_bug->id . "] Failed to create additional moz-project-review bugs:\n" .
- join("\n", @dep_errors);
- $vars->{'message'} = 'moz_project_review_creation_failed';
- }
-
- if (scalar @dep_comment) {
- my $comment = join("\n", @dep_comment);
- if (scalar @dep_errors) {
- $comment .= "\n\nSome errors occurred creating dependent bugs and have been recorded";
- }
- $parent_bug->add_comment($comment);
- $parent_bug->update($parent_bug->creation_ts);
+ $comment
+ .= "\n\nSome errors occurred creating dependent bugs and have been recorded";
}
+ $parent_bug->add_comment($comment);
+ $parent_bug->update($parent_bug->creation_ts);
+ }
- foreach my $bug_id (@send_mail) {
- Bugzilla::BugMail::Send($bug_id, { changer => Bugzilla->user });
- }
+ foreach my $bug_id (@send_mail) {
+ Bugzilla::BugMail::Send($bug_id, {changer => Bugzilla->user});
+ }
}
sub _file_child_bug {
- my ($params) = @_;
- my ($parent_bug, $template_vars, $template_suffix, $bug_data, $dep_comment, $dep_errors, $send_mail)
- = @$params{qw(parent_bug template_vars template_suffix bug_data dep_comment dep_errors send_mail)};
- my $old_error_mode = Bugzilla->error_mode;
- Bugzilla->error_mode(ERROR_MODE_DIE);
-
- my $new_bug;
- eval {
- my $comment;
- my $full_template = "bug/create/comment-shield-studies-$template_suffix.txt.tmpl";
- Bugzilla->template->process($full_template, $template_vars, \$comment)
- || ThrowTemplateError(Bugzilla->template->error());
- $bug_data->{'comment'} = $comment;
- if ($new_bug = Bugzilla::Bug->create($bug_data)) {
- my $set_all = {
- dependson => { add => [ $new_bug->bug_id ] }
- };
- $parent_bug->set_all($set_all);
- $parent_bug->update($parent_bug->creation_ts);
- }
+ my ($params) = @_;
+ my ($parent_bug, $template_vars, $template_suffix, $bug_data, $dep_comment,
+ $dep_errors, $send_mail)
+ = @$params{
+ qw(parent_bug template_vars template_suffix bug_data dep_comment dep_errors send_mail)
};
-
- if ($@ || !($new_bug && $new_bug->{'bug_id'})) {
- push(@$dep_comment, "Error creating $template_suffix review bug");
- push(@$dep_errors, "$template_suffix : $@") if $@;
- # Since we performed Bugzilla::Bug::create in an eval block, we
- # need to manually rollback the commit as this is not done
- # in Bugzilla::Error automatically for eval'ed code.
- Bugzilla->dbh->bz_rollback_transaction();
- }
- else {
- push(@$send_mail, $new_bug->id);
- push(@$dep_comment, "Bug " . $new_bug->id . " - " . $new_bug->short_desc);
+ my $old_error_mode = Bugzilla->error_mode;
+ Bugzilla->error_mode(ERROR_MODE_DIE);
+
+ my $new_bug;
+ eval {
+ my $comment;
+ my $full_template
+ = "bug/create/comment-shield-studies-$template_suffix.txt.tmpl";
+ Bugzilla->template->process($full_template, $template_vars, \$comment)
+ || ThrowTemplateError(Bugzilla->template->error());
+ $bug_data->{'comment'} = $comment;
+ if ($new_bug = Bugzilla::Bug->create($bug_data)) {
+ my $set_all = {dependson => {add => [$new_bug->bug_id]}};
+ $parent_bug->set_all($set_all);
+ $parent_bug->update($parent_bug->creation_ts);
}
+ };
+
+ if ($@ || !($new_bug && $new_bug->{'bug_id'})) {
+ push(@$dep_comment, "Error creating $template_suffix review bug");
+ push(@$dep_errors, "$template_suffix : $@") if $@;
+
+ # Since we performed Bugzilla::Bug::create in an eval block, we
+ # need to manually rollback the commit as this is not done
+ # in Bugzilla::Error automatically for eval'ed code.
+ Bugzilla->dbh->bz_rollback_transaction();
+ }
+ else {
+ push(@$send_mail, $new_bug->id);
+ push(@$dep_comment, "Bug " . $new_bug->id . " - " . $new_bug->short_desc);
+ }
- undef $@;
- Bugzilla->error_mode($old_error_mode);
+ undef $@;
+ Bugzilla->error_mode($old_error_mode);
}
sub _pre_fxos_feature {
- my ($self, $args) = @_;
- my $cgi = Bugzilla->cgi;
- my $user = Bugzilla->user;
- my $params = $args->{params};
+ my ($self, $args) = @_;
+ my $cgi = Bugzilla->cgi;
+ my $user = Bugzilla->user;
+ my $params = $args->{params};
- $params->{keywords} = 'foxfood';
- $params->{keywords} .= ',feature' if ($cgi->param('feature_type') // '') eq 'new';
- $params->{bug_status} = $user->in_group('canconfirm') ? 'NEW' : 'UNCONFIRMED';
+ $params->{keywords} = 'foxfood';
+ $params->{keywords} .= ',feature'
+ if ($cgi->param('feature_type') // '') eq 'new';
+ $params->{bug_status} = $user->in_group('canconfirm') ? 'NEW' : 'UNCONFIRMED';
}
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';
- }
+ 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
+# 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;
- }
+ 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';
+ 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',
- };
+ 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')) {
- if ($cgi->param('format') eq '__standard__') {
- $cgi->delete('format');
- $cgi->param('format_forced', 1);
- }
- } 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')));
+ 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')) {
+ if ($cgi->param('format') eq '__standard__') {
+ $cgi->delete('format');
+ $cgi->param('format_forced', 1);
+ }
+ }
+ 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}) ];
- }
- if ((Bugzilla->cgi->param('format') // '') eq 'fxos-feature') {
- $self->_pre_fxos_feature($args);
- }
+ my ($self, $args) = @_;
+ my $params = $args->{params};
+ if (exists $params->{groups}) {
+
+ # map renamed groups
+ $params->{groups} = [_map_groups($params->{groups})];
+ }
+ if ((Bugzilla->cgi->param('format') // '') eq 'fxos-feature') {
+ $self->_pre_fxos_feature($args);
+ }
}
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;
+ 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;
+ # 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) = @_;
- my $cgi = Bugzilla->cgi;
- my $user = Bugzilla->user;
- my $template = Bugzilla->template;
-
- # validate group membership
- $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) {
- # Only allow POST requests
- if ($cgi->request_method ne 'POST') {
- ThrowCodeError('illegal_request_method',
- { method => $cgi->request_method, accepted => ['POST'] });
- }
+ my ($vars) = @_;
+ my $cgi = Bugzilla->cgi;
+ my $user = Bugzilla->user;
+ my $template = Bugzilla->template;
- check_hash_token($input->{token}, ['query_database']);
- trick_taint($query);
- $vars->{executed} = 1;
+ # validate group membership
+ $user->in_group('query_database')
+ || ThrowUserError('auth_failure',
+ {group => 'query_database', action => 'access', object => 'query_database'});
- # add limit if missing
- if ($query !~ /\sLIMIT\s+\d+\s*$/si) {
- $query .= ' LIMIT 1000';
- $vars->{query} = $query;
- }
+ # read query
+ my $input = Bugzilla->input_params;
+ my $query = $input->{query};
+ $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;
- }
+ if ($query) {
- # build result
- my $columns = $sth->{NAME};
- my $rows;
- while (my @row = $sth->fetchrow_array) {
- push @$rows, \@row;
- }
+ # Only allow POST requests
+ if ($cgi->request_method ne 'POST') {
+ ThrowCodeError('illegal_request_method',
+ {method => $cgi->request_method, accepted => ['POST']});
+ }
- # return results
- $vars->{columns} = $columns;
- $vars->{rows} = $rows;
+ check_hash_token($input->{token}, ['query_database']);
+ trick_taint($query);
+ $vars->{executed} = 1;
- if ($input->{csv}) {
- print $cgi->header(-type=> 'text/csv',
- -content_disposition=> "attachment; filename=\"query_database.csv\"");
- $template->process("pages/query_database.csv.tmpl", $vars)
- || ThrowTemplateError($template->error());
- exit;
- }
+ # 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;
+
+ if ($input->{csv}) {
+ print $cgi->header(
+ -type => 'text/csv',
+ -content_disposition => "attachment; filename=\"query_database.csv\""
+ );
+ $template->process("pages/query_database.csv.tmpl", $vars)
+ || ThrowTemplateError($template->error());
+ exit;
+ }
+ }
}
# 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);
+ my ($self, $group) = @_;
+ return $group->name eq $self->default_security_group
+ || ((grep { $_ eq $group->name } @always_fileable_groups) ? 1 : 0);
}
sub _default_security_group {
- return $_[0]->default_security_group_obj->name;
+ return $_[0]->default_security_group_obj->name;
}
sub _default_security_group_obj {
- my $group_id = $_[0]->{security_group_id};
- if (!$group_id) {
- return Bugzilla::Group->new({ name => Bugzilla->params->{insidergroup}, cache => 1 });
- }
- return Bugzilla::Group->new({ id => $group_id, cache => 1 });
+ my $group_id = $_[0]->{security_group_id};
+ if (!$group_id) {
+ return Bugzilla::Group->new(
+ {name => Bugzilla->params->{insidergroup}, cache => 1});
+ }
+ return Bugzilla::Group->new({id => $group_id, 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);
- }
+ 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 $create_files = $args->{create_files};
- my $extensions_dir = bz_locations()->{extensionsdir};
- $create_files->{__lbheartbeat__} = {
- perms => Bugzilla::Install::Filesystem::WS_SERVE,
- overwrite => 1, # the original value for this was wrong, overwrite it
- contents => 'httpd OK',
- };
-
-
- # version.json needs to have a source attribute pointing to
- # our repository. We already have this information in the (static)
- # contribute.json file, so parse that in
- my $json = JSON::XS->new->pretty->utf8->canonical();
- my $contribute = eval {
- $json->decode(scalar read_file(bz_locations()->{cgi_path} . "/contribute.json"));
- };
-
- if (!$contribute) {
- die "Missing or invalid contribute.json file";
- }
-
- my $version_obj = {
- source => $contribute->{repository}{url},
- version => BUGZILLA_VERSION,
- commit => $ENV{CIRCLE_SHA1} // 'unknown',
- build => $ENV{CIRCLE_BUILD_URL} // 'unknown',
- };
-
- $create_files->{'version.json'} = {
- overwrite => 1,
- perms => Bugzilla::Install::Filesystem::WS_SERVE,
- contents => $json->encode($version_obj),
- };
-
- $files->{"$extensions_dir/BMO/bin/migrate-github-pull-requests.pl"} = {
- perms => Bugzilla::Install::Filesystem::OWNER_EXECUTE
- };
+ my ($self, $args) = @_;
+ my $files = $args->{files};
+ my $create_files = $args->{create_files};
+ my $extensions_dir = bz_locations()->{extensionsdir};
+ $create_files->{__lbheartbeat__} = {
+ perms => Bugzilla::Install::Filesystem::WS_SERVE,
+ overwrite => 1, # the original value for this was wrong, overwrite it
+ contents => 'httpd OK',
+ };
+
+
+ # version.json needs to have a source attribute pointing to
+ # our repository. We already have this information in the (static)
+ # contribute.json file, so parse that in
+ my $json = JSON::XS->new->pretty->utf8->canonical();
+ my $contribute = eval {
+ $json->decode(
+ scalar read_file(bz_locations()->{cgi_path} . "/contribute.json"));
+ };
+
+ if (!$contribute) {
+ die "Missing or invalid contribute.json file";
+ }
+
+ my $version_obj = {
+ source => $contribute->{repository}{url},
+ version => BUGZILLA_VERSION,
+ commit => $ENV{CIRCLE_SHA1} // 'unknown',
+ build => $ENV{CIRCLE_BUILD_URL} // 'unknown',
+ };
+
+ $create_files->{'version.json'} = {
+ overwrite => 1,
+ perms => Bugzilla::Install::Filesystem::WS_SERVE,
+ contents => $json->encode($version_obj),
+ };
+
+ $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 => \&get_all_group_names,
- default => 'admin',
- checker => \&check_group
+ my ($self, $args) = @_;
+ push @{$args->{panels}->{groupsecurity}->{params}},
+ {
+ name => 'delete_comments_group',
+ type => 's',
+ choices => \&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' });
- }
+ 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' });
- }
+ 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;
+ *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;
+ 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;
- }
+ 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;
+ }
}
+ }
}
sub _split_crash_signature {
- my ($self, $vars) = @_;
- my $bug = $vars->{bug} // return;
- my $crash_signature = $bug->cf_crash_signature // return;
- return [
- grep { /\S/ }
- extract_multiple($crash_signature, [ sub { extract_bracketed($_[0], '[]') } ])
- ];
+ my ($self, $vars) = @_;
+ my $bug = $vars->{bug} // return;
+ my $crash_signature = $bug->cf_crash_signature // return;
+ return [grep {/\S/}
+ extract_multiple($crash_signature, [sub { extract_bracketed($_[0], '[]') }])];
}
sub enter_bug_entrydefaultvars {
- my ($self, $args) = @_;
- my $vars = $args->{vars};
- my $cgi = Bugzilla->cgi;
- return unless my $format = $cgi->param('format');
-
- if ($format eq 'fxos-feature') {
- $vars->{feature_type} = $cgi->param('feature_type');
- $vars->{description} = $cgi->param('description');
- $vars->{discussion} = $cgi->param('discussion');
- }
+ my ($self, $args) = @_;
+ my $vars = $args->{vars};
+ my $cgi = Bugzilla->cgi;
+ return unless my $format = $cgi->param('format');
+
+ if ($format eq 'fxos-feature') {
+ $vars->{feature_type} = $cgi->param('feature_type');
+ $vars->{description} = $cgi->param('description');
+ $vars->{discussion} = $cgi->param('discussion');
+ }
}
sub app_startup {
- my ($self, $args) = @_;
- my $app = $args->{app};
- my $r = $app->routes;
-
- $r->get(
- '/favicon.ico' => sub {
- my $c = shift;
- $c->reply->file(
- $c->app->home->child('extensions/BMO/web/images/favicon.ico')
- );
- }
+ my ($self, $args) = @_;
+ my $app = $args->{app};
+ my $r = $app->routes;
+
+ $r->get(
+ '/favicon.ico' => sub {
+ my $c = shift;
+ $c->reply->file($c->app->home->child('extensions/BMO/web/images/favicon.ico'));
+ }
+ );
+
+ $r->any('/:REWRITE_itrequest' => [REWRITE_itrequest => qr{form[\.:]itrequest}])
+ ->to('CGI#enter_bug_cgi' =>
+ {'product' => 'Infrastructure & Operations', 'format' => 'itrequest'});
+ $r->any('/:REWRITE_mozlist' => [REWRITE_mozlist => qr{form[\.:]mozlist}])
+ ->to(
+ 'CGI#enter_bug_cgi' => {'product' => 'mozilla.org', 'format' => 'mozlist'});
+ $r->any('/:REWRITE_poweredby' => [REWRITE_poweredby => qr{form[\.:]poweredby}])
+ ->to(
+ 'CGI#enter_bug_cgi' => {'product' => 'mozilla.org', 'format' => 'poweredby'});
+ $r->any(
+ '/:REWRITE_presentation' => [REWRITE_presentation => qr{form[\.:]presentation}])
+ ->to(
+ 'cgi#enter_bug_cgi' => {'product' => 'mozilla.org', 'format' => 'presentation'}
);
-
- $r->any( '/:REWRITE_itrequest' => [ REWRITE_itrequest => qr{form[\.:]itrequest} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Infrastructure & Operations', 'format' => 'itrequest' } );
- $r->any( '/:REWRITE_mozlist' => [ REWRITE_mozlist => qr{form[\.:]mozlist} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'mozilla.org', 'format' => 'mozlist' } );
- $r->any( '/:REWRITE_poweredby' => [ REWRITE_poweredby => qr{form[\.:]poweredby} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'mozilla.org', 'format' => 'poweredby' } );
- $r->any( '/:REWRITE_presentation' => [ REWRITE_presentation => qr{form[\.:]presentation} ] )
- ->to( 'cgi#enter_bug_cgi' => { 'product' => 'mozilla.org', 'format' => 'presentation' } );
- $r->any( '/:REWRITE_trademark' => [ REWRITE_trademark => qr{form[\.:]trademark} ] )
- ->to( 'cgi#enter_bug_cgi' => { 'product' => 'mozilla.org', 'format' => 'trademark' } );
- $r->any( '/:REWRITE_recoverykey' => [ REWRITE_recoverykey => qr{form[\.:]recoverykey} ] )
- ->to( 'cgi#enter_bug_cgi' => { 'product' => 'mozilla.org', 'format' => 'recoverykey' } );
- $r->any( '/:REWRITE_legal' => [ REWRITE_legal => qr{form[\.:]legal} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Legal', 'format' => 'legal' }, );
- $r->any( '/:REWRITE_recruiting' => [ REWRITE_recruiting => qr{form[\.:]recruiting} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Recruiting', 'format' => 'recruiting' } );
- $r->any( '/:REWRITE_intern' => [ REWRITE_intern => qr{form[\.:]intern} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Recruiting', 'format' => 'intern' } );
- $r->any( '/:REWRITE_mozpr' => [ REWRITE_mozpr => qr{form[\.:]mozpr} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Mozilla PR', 'format' => 'mozpr' }, );
- $r->any( '/:REWRITE_reps_mentorship' => [ REWRITE_reps_mentorship => qr{form[\.:]reps[\.:]mentorship} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Mozilla Reps', 'format' => 'mozreps' }, );
- $r->any( '/:REWRITE_reps_budget' => [ REWRITE_reps_budget => qr{form[\.:]reps[\.:]budget} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Mozilla Reps', 'format' => 'remo-budget' } );
- $r->any( '/:REWRITE_reps_swag' => [ REWRITE_reps_swag => qr{form[\.:]reps[\.:]swag} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Mozilla Reps', 'format' => 'remo-swag' } );
- $r->any( '/:REWRITE_reps_it' => [ REWRITE_reps_it => qr{form[\.:]reps[\.:]it} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Mozilla Reps', 'format' => 'remo-it' } );
- $r->any( '/:REWRITE_reps_payment' => [ REWRITE_reps_payment => qr{form[\.:]reps[\.:]payment} ] )
- ->to( 'CGI#page_cgi' => { 'id' => 'remo-form-payment.html' } );
- $r->any( '/:REWRITE_csa_discourse' => [ REWRITE_csa_discourse => qr{form[\.:]csa[\.:]discourse} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Infrastructure & Operations', 'format' => 'csa-discourse' } );
- $r->any( '/:REWRITE_employee_incident' => [ REWRITE_employee_incident => qr{form[\.:]employee[\.\-:]incident} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'mozilla.org', 'format' => 'employee-incident' } );
- $r->any( '/:REWRITE_brownbag' => [ REWRITE_brownbag => qr{form[\.:]brownbag} ] )
- ->to( 'CGI#https_air_mozilla_org_requests' => {} );
- $r->any( '/:REWRITE_finance' => [ REWRITE_finance => qr{form[\.:]finance} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Finance', 'format' => 'finance' } );
- $r->any(
- '/:REWRITE_moz_project_review' => [ REWRITE_moz_project_review => qr{form[\.:]moz[\.\-:]project[\.\-:]review} ]
- )->to( 'CGI#enter_bug_cgi' => { 'product' => 'mozilla.org', 'format' => 'moz-project-review' } );
- $r->any( '/:REWRITE_docs' => [ REWRITE_docs => qr{form[\.:]docs?} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Developer Documentation', 'format' => 'doc' } );
- $r->any( '/:REWRITE_mdn' => [ REWRITE_mdn => qr{form[\.:]mdn?} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'format' => 'mdn', 'product' => 'developer.mozilla.org' } );
- $r->any( '/:REWRITE_swag_gear' => [ REWRITE_swag_gear => qr{form[\.:](swag|gear)} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'format' => 'swag', 'product' => 'Marketing' } );
- $r->any( '/:REWRITE_costume' => [ REWRITE_costume => qr{form[\.:]costume} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Marketing', 'format' => 'costume' } );
- $r->any( '/:REWRITE_ipp' => [ REWRITE_ipp => qr{form[\.:]ipp} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Internet Public Policy', 'format' => 'ipp' } );
- $r->any( '/:REWRITE_creative' => [ REWRITE_creative => qr{form[\.:]creative} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'format' => 'creative', 'product' => 'Marketing' } );
- $r->any( '/:REWRITE_user_engagement' => [ REWRITE_user_engagement => qr{form[\.:]user[\.\-:]engagement} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'format' => 'user-engagement', 'product' => 'Marketing' } );
- $r->any( '/:REWRITE_dev_engagement_event' =>
- [ REWRITE_dev_engagement_event => qr{form[\.:]dev[\.\-:]engagement[\.\-\:]event} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Developer Engagement', 'format' => 'dev-engagement-event' } );
- $r->any( '/:REWRITE_mobile_compat' => [ REWRITE_mobile_compat => qr{form[\.:]mobile[\.\-:]compat} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Tech Evangelism', 'format' => 'mobile-compat' } );
- $r->any( '/:REWRITE_web_bounty' => [ REWRITE_web_bounty => qr{form[\.:]web[\.:]bounty} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'format' => 'web-bounty', 'product' => 'mozilla.org' } );
- $r->any( '/:REWRITE_automative' => [ REWRITE_automative => qr{form[\.:]automative} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Testing', 'format' => 'automative' } );
- $r->any( '/:REWRITE_comm_newsletter' => [ REWRITE_comm_newsletter => qr{form[\.:]comm[\.:]newsletter} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'format' => 'comm-newsletter', 'product' => 'Marketing' } );
- $r->any( '/:REWRITE_screen_share_whitelist' =>
- [ REWRITE_screen_share_whitelist => qr{form[\.:]screen[\.:]share[\.:]whitelist} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'format' => 'screen-share-whitelist', 'product' => 'Firefox' } );
- $r->any( '/:REWRITE_data_compliance' => [ REWRITE_data_compliance => qr{form[\.:]data[\.\-:]compliance} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Data Compliance', 'format' => 'data-compliance' } );
- $r->any( '/:REWRITE_fsa_budget' => [ REWRITE_fsa_budget => qr{form[\.:]fsa[\.:]budget} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'FSA', 'format' => 'fsa-budget' } );
- $r->any( '/:REWRITE_triage_request' => [ REWRITE_triage_request => qr{form[\.:]triage[\.\-]request} ] )
- ->to( 'CGI#page_cgi' => { 'id' => 'triage_request.html' } );
- $r->any( '/:REWRITE_crm_CRM' => [ REWRITE_crm_CRM => qr{form[\.:](crm|CRM)} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'format' => 'crm', 'product' => 'Marketing' } );
- $r->any( '/:REWRITE_nda' => [ REWRITE_nda => qr{form[\.:]nda} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Legal', 'format' => 'nda' } );
- $r->any( '/:REWRITE_name_clearance' => [ REWRITE_name_clearance => qr{form[\.:]name[\.:]clearance} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'format' => 'name-clearance', 'product' => 'Legal' } );
- $r->any( '/:REWRITE_shield_studies' => [ REWRITE_shield_studies => qr{form[\.:]shield[\.:]studies} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Shield', 'format' => 'shield-studies' } );
- $r->any( '/:REWRITE_client_bounty' => [ REWRITE_client_bounty => qr{form[\.:]client[\.:]bounty} ] )
- ->to( 'CGI#enter_bug_cgi' => { 'product' => 'Firefox', 'format' => 'client-bounty' } );
+ $r->any('/:REWRITE_trademark' => [REWRITE_trademark => qr{form[\.:]trademark}])
+ ->to(
+ 'cgi#enter_bug_cgi' => {'product' => 'mozilla.org', 'format' => 'trademark'});
+ $r->any(
+ '/:REWRITE_recoverykey' => [REWRITE_recoverykey => qr{form[\.:]recoverykey}])
+ ->to(
+ 'cgi#enter_bug_cgi' => {'product' => 'mozilla.org', 'format' => 'recoverykey'});
+ $r->any('/:REWRITE_legal' => [REWRITE_legal => qr{form[\.:]legal}])
+ ->to('CGI#enter_bug_cgi' => {'product' => 'Legal', 'format' => 'legal'},);
+ $r->any(
+ '/:REWRITE_recruiting' => [REWRITE_recruiting => qr{form[\.:]recruiting}])
+ ->to(
+ 'CGI#enter_bug_cgi' => {'product' => 'Recruiting', 'format' => 'recruiting'});
+ $r->any('/:REWRITE_intern' => [REWRITE_intern => qr{form[\.:]intern}])
+ ->to(
+ 'CGI#enter_bug_cgi' => {'product' => 'Recruiting', 'format' => 'intern'});
+ $r->any('/:REWRITE_mozpr' => [REWRITE_mozpr => qr{form[\.:]mozpr}])
+ ->to('CGI#enter_bug_cgi' => {'product' => 'Mozilla PR', 'format' => 'mozpr'},
+ );
+ $r->any('/:REWRITE_reps_mentorship' =>
+ [REWRITE_reps_mentorship => qr{form[\.:]reps[\.:]mentorship}])
+ ->to(
+ 'CGI#enter_bug_cgi' => {'product' => 'Mozilla Reps', 'format' => 'mozreps'},);
+ $r->any('/:REWRITE_reps_budget' =>
+ [REWRITE_reps_budget => qr{form[\.:]reps[\.:]budget}])
+ ->to(
+ 'CGI#enter_bug_cgi' => {'product' => 'Mozilla Reps', 'format' => 'remo-budget'}
+ );
+ $r->any(
+ '/:REWRITE_reps_swag' => [REWRITE_reps_swag => qr{form[\.:]reps[\.:]swag}])
+ ->to(
+ 'CGI#enter_bug_cgi' => {'product' => 'Mozilla Reps', 'format' => 'remo-swag'});
+ $r->any('/:REWRITE_reps_it' => [REWRITE_reps_it => qr{form[\.:]reps[\.:]it}])
+ ->to(
+ 'CGI#enter_bug_cgi' => {'product' => 'Mozilla Reps', 'format' => 'remo-it'});
+ $r->any('/:REWRITE_reps_payment' =>
+ [REWRITE_reps_payment => qr{form[\.:]reps[\.:]payment}])
+ ->to('CGI#page_cgi' => {'id' => 'remo-form-payment.html'});
+ $r->any('/:REWRITE_csa_discourse' =>
+ [REWRITE_csa_discourse => qr{form[\.:]csa[\.:]discourse}])
+ ->to('CGI#enter_bug_cgi' =>
+ {'product' => 'Infrastructure & Operations', 'format' => 'csa-discourse'});
+ $r->any('/:REWRITE_employee_incident' =>
+ [REWRITE_employee_incident => qr{form[\.:]employee[\.\-:]incident}])
+ ->to('CGI#enter_bug_cgi' =>
+ {'product' => 'mozilla.org', 'format' => 'employee-incident'});
+ $r->any('/:REWRITE_brownbag' => [REWRITE_brownbag => qr{form[\.:]brownbag}])
+ ->to('CGI#https_air_mozilla_org_requests' => {});
+ $r->any('/:REWRITE_finance' => [REWRITE_finance => qr{form[\.:]finance}])
+ ->to('CGI#enter_bug_cgi' => {'product' => 'Finance', 'format' => 'finance'});
+ $r->any('/:REWRITE_moz_project_review' =>
+ [REWRITE_moz_project_review => qr{form[\.:]moz[\.\-:]project[\.\-:]review}])
+ ->to('CGI#enter_bug_cgi' =>
+ {'product' => 'mozilla.org', 'format' => 'moz-project-review'});
+ $r->any('/:REWRITE_docs' => [REWRITE_docs => qr{form[\.:]docs?}])
+ ->to('CGI#enter_bug_cgi' =>
+ {'product' => 'Developer Documentation', 'format' => 'doc'});
+ $r->any('/:REWRITE_mdn' => [REWRITE_mdn => qr{form[\.:]mdn?}])
+ ->to('CGI#enter_bug_cgi' =>
+ {'format' => 'mdn', 'product' => 'developer.mozilla.org'});
+ $r->any(
+ '/:REWRITE_swag_gear' => [REWRITE_swag_gear => qr{form[\.:](swag|gear)}])
+ ->to('CGI#enter_bug_cgi' => {'format' => 'swag', 'product' => 'Marketing'});
+ $r->any('/:REWRITE_costume' => [REWRITE_costume => qr{form[\.:]costume}])
+ ->to(
+ 'CGI#enter_bug_cgi' => {'product' => 'Marketing', 'format' => 'costume'});
+ $r->any('/:REWRITE_ipp' => [REWRITE_ipp => qr{form[\.:]ipp}])
+ ->to('CGI#enter_bug_cgi' =>
+ {'product' => 'Internet Public Policy', 'format' => 'ipp'});
+ $r->any('/:REWRITE_creative' => [REWRITE_creative => qr{form[\.:]creative}])
+ ->to(
+ 'CGI#enter_bug_cgi' => {'format' => 'creative', 'product' => 'Marketing'});
+ $r->any('/:REWRITE_user_engagement' =>
+ [REWRITE_user_engagement => qr{form[\.:]user[\.\-:]engagement}])
+ ->to('CGI#enter_bug_cgi' =>
+ {'format' => 'user-engagement', 'product' => 'Marketing'});
+ $r->any(
+ '/:REWRITE_dev_engagement_event' => [
+ REWRITE_dev_engagement_event => qr{form[\.:]dev[\.\-:]engagement[\.\-\:]event}
+ ]
+ )
+ ->to('CGI#enter_bug_cgi' =>
+ {'product' => 'Developer Engagement', 'format' => 'dev-engagement-event'});
+ $r->any('/:REWRITE_mobile_compat' =>
+ [REWRITE_mobile_compat => qr{form[\.:]mobile[\.\-:]compat}])
+ ->to('CGI#enter_bug_cgi' =>
+ {'product' => 'Tech Evangelism', 'format' => 'mobile-compat'});
+ $r->any(
+ '/:REWRITE_web_bounty' => [REWRITE_web_bounty => qr{form[\.:]web[\.:]bounty}])
+ ->to(
+ 'CGI#enter_bug_cgi' => {'format' => 'web-bounty', 'product' => 'mozilla.org'});
+ $r->any(
+ '/:REWRITE_automative' => [REWRITE_automative => qr{form[\.:]automative}])
+ ->to(
+ 'CGI#enter_bug_cgi' => {'product' => 'Testing', 'format' => 'automative'});
+ $r->any('/:REWRITE_comm_newsletter' =>
+ [REWRITE_comm_newsletter => qr{form[\.:]comm[\.:]newsletter}])
+ ->to('CGI#enter_bug_cgi' =>
+ {'format' => 'comm-newsletter', 'product' => 'Marketing'});
+ $r->any(
+ '/:REWRITE_screen_share_whitelist' => [
+ REWRITE_screen_share_whitelist => qr{form[\.:]screen[\.:]share[\.:]whitelist}
+ ]
+ )
+ ->to('CGI#enter_bug_cgi' =>
+ {'format' => 'screen-share-whitelist', 'product' => 'Firefox'});
+ $r->any('/:REWRITE_data_compliance' =>
+ [REWRITE_data_compliance => qr{form[\.:]data[\.\-:]compliance}])
+ ->to('CGI#enter_bug_cgi' =>
+ {'product' => 'Data Compliance', 'format' => 'data-compliance'});
+ $r->any(
+ '/:REWRITE_fsa_budget' => [REWRITE_fsa_budget => qr{form[\.:]fsa[\.:]budget}])
+ ->to('CGI#enter_bug_cgi' => {'product' => 'FSA', 'format' => 'fsa-budget'});
+ $r->any('/:REWRITE_triage_request' =>
+ [REWRITE_triage_request => qr{form[\.:]triage[\.\-]request}])
+ ->to('CGI#page_cgi' => {'id' => 'triage_request.html'});
+ $r->any('/:REWRITE_crm_CRM' => [REWRITE_crm_CRM => qr{form[\.:](crm|CRM)}])
+ ->to('CGI#enter_bug_cgi' => {'format' => 'crm', 'product' => 'Marketing'});
+ $r->any('/:REWRITE_nda' => [REWRITE_nda => qr{form[\.:]nda}])
+ ->to('CGI#enter_bug_cgi' => {'product' => 'Legal', 'format' => 'nda'});
+ $r->any('/:REWRITE_name_clearance' =>
+ [REWRITE_name_clearance => qr{form[\.:]name[\.:]clearance}])
+ ->to(
+ 'CGI#enter_bug_cgi' => {'format' => 'name-clearance', 'product' => 'Legal'});
+ $r->any('/:REWRITE_shield_studies' =>
+ [REWRITE_shield_studies => qr{form[\.:]shield[\.:]studies}])
+ ->to(
+ 'CGI#enter_bug_cgi' => {'product' => 'Shield', 'format' => 'shield-studies'});
+ $r->any('/:REWRITE_client_bounty' =>
+ [REWRITE_client_bounty => qr{form[\.:]client[\.:]bounty}])
+ ->to(
+ 'CGI#enter_bug_cgi' => {'product' => 'Firefox', 'format' => 'client-bounty'});
}
__PACKAGE__->NAME;
diff --git a/extensions/BMO/bin/bug_1022707.pl b/extensions/BMO/bin/bug_1022707.pl
index 4d48db01d..31afa7d05 100755
--- a/extensions/BMO/bin/bug_1022707.pl
+++ b/extensions/BMO/bin/bug_1022707.pl
@@ -37,8 +37,10 @@ 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);
+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);
diff --git a/extensions/BMO/bin/bug_1093952.pl b/extensions/BMO/bin/bug_1093952.pl
index fd891f4ae..f52427284 100755
--- a/extensions/BMO/bin/bug_1093952.pl
+++ b/extensions/BMO/bin/bug_1093952.pl
@@ -23,14 +23,17 @@ Bugzilla->usage_mode(USAGE_MODE_CMDLINE);
my $dbh = Bugzilla->dbh;
-my $infra = Bugzilla::Product->check({ name => 'Infrastructure & Operations' });
-my $relops_id = Bugzilla::Component->check({ product => $infra, name => 'RelOps' })->id;
-my $puppet_id = Bugzilla::Component->check({ product => $infra, name => 'RelOps: Puppet' })->id;
-my $infra_id = $infra->id;
-my $components = $dbh->sql_in('component_id', [ $relops_id, $puppet_id ]);
+my $infra = Bugzilla::Product->check({name => 'Infrastructure & Operations'});
+my $relops_id
+ = Bugzilla::Component->check({product => $infra, name => 'RelOps'})->id;
+my $puppet_id
+ = Bugzilla::Component->check({product => $infra, name => 'RelOps: Puppet'})
+ ->id;
+my $infra_id = $infra->id;
+my $components = $dbh->sql_in('component_id', [$relops_id, $puppet_id]);
print "Searching for bugs..\n";
-my $bugs = $dbh->selectall_arrayref(<<EOF, { Slice => {} });
+my $bugs = $dbh->selectall_arrayref(<<EOF, {Slice => {}});
SELECT
bug_id,
product_id,
@@ -52,9 +55,9 @@ printf "About to fix %s bugs\n", scalar(@$bugs);
print "Press <Ctrl-C> to stop or <Enter> to continue...\n";
getc();
-my $nobody = Bugzilla::User->check({ name => Bugzilla->params->{'nobody_user'} });
-my $field = Bugzilla::Field->check({ name => 'status_whiteboard' });
-my $when = $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
+my $nobody = Bugzilla::User->check({name => Bugzilla->params->{'nobody_user'}});
+my $field = Bugzilla::Field->check({name => 'status_whiteboard'});
+my $when = $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
my $sth_bugs = $dbh->prepare("
UPDATE bugs
@@ -70,22 +73,25 @@ my $sth_activity = $dbh->prepare("
$dbh->bz_start_transaction();
foreach my $bug (@$bugs) {
- my $bug_id = $bug->{bug_id};
- my $whiteboard = $bug->{status_whiteboard};
- print "bug $bug_id\n $whiteboard\n";
+ my $bug_id = $bug->{bug_id};
+ my $whiteboard = $bug->{status_whiteboard};
+ print "bug $bug_id\n $whiteboard\n";
- my $updated = $whiteboard;
- $updated =~ s#\[kanban:engops:https://kanbanize\.com/ctrl_board/6/[^\]]*\]\s*##g;
- if ($bug->{product_id} == $infra->id
- && $bug->{component_id} != $relops_id
- && $bug->{component_id} != $puppet_id
- ) {
- $updated =~ s#\[kanban:engops:https://mozilla\.kanbanize\.com/ctrl_board/6/[^\]]*\]\s*##g;
- }
- print " $updated\n";
+ my $updated = $whiteboard;
+ $updated
+ =~ s#\[kanban:engops:https://kanbanize\.com/ctrl_board/6/[^\]]*\]\s*##g;
+ if ( $bug->{product_id} == $infra->id
+ && $bug->{component_id} != $relops_id
+ && $bug->{component_id} != $puppet_id)
+ {
+ $updated
+ =~ s#\[kanban:engops:https://mozilla\.kanbanize\.com/ctrl_board/6/[^\]]*\]\s*##g;
+ }
+ print " $updated\n";
- $sth_bugs->execute($updated, $when, $when, $bug_id);
- $sth_activity->execute($bug_id, $nobody->id, $when, $field->id, $whiteboard, $updated);
+ $sth_bugs->execute($updated, $when, $when, $bug_id);
+ $sth_activity->execute($bug_id, $nobody->id, $when, $field->id, $whiteboard,
+ $updated);
}
$dbh->bz_commit_transaction();
diff --git a/extensions/BMO/bin/bug_1141452.pl b/extensions/BMO/bin/bug_1141452.pl
index 155c4704c..56b63db91 100755
--- a/extensions/BMO/bin/bug_1141452.pl
+++ b/extensions/BMO/bin/bug_1141452.pl
@@ -13,8 +13,8 @@ use 5.10.1;
use lib qw(. lib local/lib/perl5);
BEGIN {
- use Bugzilla;
- Bugzilla->extensions;
+ use Bugzilla;
+ Bugzilla->extensions;
}
use Bugzilla::Constants qw( USAGE_MODE_CMDLINE );
@@ -24,14 +24,17 @@ use Bugzilla::User;
Bugzilla->usage_mode(USAGE_MODE_CMDLINE);
my $dbh = Bugzilla->dbh;
-my $blocking_b2g = Bugzilla::Extension::TrackingFlags::Flag->check({ name => 'cf_blocking_b2g' });
-my $tracking_b2g = Bugzilla::Extension::TrackingFlags::Flag->check({ name => 'cf_tracking_b2g' });
+my $blocking_b2g = Bugzilla::Extension::TrackingFlags::Flag->check(
+ {name => 'cf_blocking_b2g'});
+my $tracking_b2g = Bugzilla::Extension::TrackingFlags::Flag->check(
+ {name => 'cf_tracking_b2g'});
die "tracking-b2g does not have a 'backlog' value\n"
- unless grep { $_->value eq 'backlog' } @{ $tracking_b2g->values };
+ unless grep { $_->value eq 'backlog' } @{$tracking_b2g->values};
print "Searching for bugs..\n";
-my $flags = $dbh->selectall_arrayref(<<EOF, { Slice => {} }, $blocking_b2g->flag_id, $tracking_b2g->flag_id);
+my $flags = $dbh->selectall_arrayref(
+ <<EOF, {Slice => {}}, $blocking_b2g->flag_id, $tracking_b2g->flag_id);
SELECT
bugs.bug_id,
blocking_b2g.id id,
@@ -50,54 +53,59 @@ printf "About to fix %s bugs\n", scalar(@$flags);
print "Press <Ctrl-C> to stop or <Enter> to continue...\n";
getc();
-my $nobody = Bugzilla::User->check({ name => Bugzilla->params->{'nobody_user'} });
-my $when = $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
+my $nobody = Bugzilla::User->check({name => Bugzilla->params->{'nobody_user'}});
+my $when = $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
$dbh->bz_start_transaction();
foreach my $flag (@$flags) {
- if (!$flag->{value}) {
- print $flag->{bug_id}, ": changing blocking_b2g:backlog -> tracking_b2g:backlog\n";
- # no tracking_b2g value, change blocking_b2g:backlog -> tracking_b2g:backlog
- $dbh->do(
- "UPDATE tracking_flags_bugs SET tracking_flag_id = ? WHERE id = ?",
- undef,
- $tracking_b2g->flag_id, $flag->{id},
- );
- $dbh->do(
- "UPDATE bugs SET delta_ts = ?, lastdiffed = ? WHERE bug_id = ?",
- undef,
- $when, $when, $flag->{bug_id},
- );
- $dbh->do(
- "INSERT INTO bugs_activity(bug_id, who, bug_when, fieldid, removed, added) VALUES (?, ?, ?, ?, ?, ?)",
- undef,
- $flag->{bug_id}, $nobody->id, $when, $blocking_b2g->id, 'backlog', '---',
- );
- $dbh->do(
- "INSERT INTO bugs_activity(bug_id, who, bug_when, fieldid, removed, added) VALUES (?, ?, ?, ?, ?, ?)",
- undef,
- $flag->{bug_id}, $nobody->id, $when, $tracking_b2g->id, '---', 'backlog',
- );
- }
- elsif ($flag->{value}) {
- print $flag->{bug_id}, ": deleting blocking_b2g:backlog\n";
- # tracking_b2g already has a value, just delete blocking_b2g:backlog
- $dbh->do(
- "DELETE FROM tracking_flags_bugs WHERE id = ?",
- undef,
- $flag->{id},
- );
- $dbh->do(
- "UPDATE bugs SET delta_ts = ?, lastdiffed = ? WHERE bug_id = ?",
- undef,
- $when, $when, $flag->{bug_id},
- );
- $dbh->do(
- "INSERT INTO bugs_activity(bug_id, who, bug_when, fieldid, removed, added) VALUES (?, ?, ?, ?, ?, ?)",
- undef,
- $flag->{bug_id}, $nobody->id, $when, $blocking_b2g->id, 'backlog', '---',
- );
- }
+ if (!$flag->{value}) {
+ print $flag->{bug_id},
+ ": changing blocking_b2g:backlog -> tracking_b2g:backlog\n";
+
+ # no tracking_b2g value, change blocking_b2g:backlog -> tracking_b2g:backlog
+ $dbh->do("UPDATE tracking_flags_bugs SET tracking_flag_id = ? WHERE id = ?",
+ undef, $tracking_b2g->flag_id, $flag->{id},);
+ $dbh->do("UPDATE bugs SET delta_ts = ?, lastdiffed = ? WHERE bug_id = ?",
+ undef, $when, $when, $flag->{bug_id},);
+ $dbh->do(
+ "INSERT INTO bugs_activity(bug_id, who, bug_when, fieldid, removed, added) VALUES (?, ?, ?, ?, ?, ?)",
+ undef,
+ $flag->{bug_id},
+ $nobody->id,
+ $when,
+ $blocking_b2g->id,
+ 'backlog',
+ '---',
+ );
+ $dbh->do(
+ "INSERT INTO bugs_activity(bug_id, who, bug_when, fieldid, removed, added) VALUES (?, ?, ?, ?, ?, ?)",
+ undef,
+ $flag->{bug_id},
+ $nobody->id,
+ $when,
+ $tracking_b2g->id,
+ '---',
+ 'backlog',
+ );
+ }
+ elsif ($flag->{value}) {
+ print $flag->{bug_id}, ": deleting blocking_b2g:backlog\n";
+
+ # tracking_b2g already has a value, just delete blocking_b2g:backlog
+ $dbh->do("DELETE FROM tracking_flags_bugs WHERE id = ?", undef, $flag->{id},);
+ $dbh->do("UPDATE bugs SET delta_ts = ?, lastdiffed = ? WHERE bug_id = ?",
+ undef, $when, $when, $flag->{bug_id},);
+ $dbh->do(
+ "INSERT INTO bugs_activity(bug_id, who, bug_when, fieldid, removed, added) VALUES (?, ?, ?, ?, ?, ?)",
+ undef,
+ $flag->{bug_id},
+ $nobody->id,
+ $when,
+ $blocking_b2g->id,
+ 'backlog',
+ '---',
+ );
+ }
}
$dbh->bz_commit_transaction();
diff --git a/extensions/BMO/bin/migrate-github-pull-requests.pl b/extensions/BMO/bin/migrate-github-pull-requests.pl
index c39778a4a..c8afdedfb 100755
--- a/extensions/BMO/bin/migrate-github-pull-requests.pl
+++ b/extensions/BMO/bin/migrate-github-pull-requests.pl
@@ -22,9 +22,9 @@ 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 => Bugzilla->params->{'nobody_user'} });
-my $field = Bugzilla::Field->check({ name => 'attachments.mimetype' });
+my $dbh = Bugzilla->dbh;
+my $nobody = Bugzilla::User->check({name => Bugzilla->params->{'nobody_user'}});
+my $field = Bugzilla::Field->check({name => 'attachments.mimetype'});
# grab list of suitable attachments
@@ -42,7 +42,7 @@ SELECT attachments.attach_id,
AND LENGTH(thedata) <= 256
EOF
print "Searching for suitable attachments..\n";
-my $attachments = $dbh->selectall_arrayref($sql, { Slice => {} });
+my $attachments = $dbh->selectall_arrayref($sql, {Slice => {}});
my ($current, $total, $updated) = (1, scalar(@$attachments), 0);
die "No suitable attachments found\n" unless $total;
@@ -52,39 +52,32 @@ 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,
- 'text/x-github-pull-request', $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}, 'text/x-github-pull-request'
- );
- $dbh->do(
- "UPDATE bugs SET delta_ts = ?, lastdiffed = ? WHERE bug_id = ?",
- undef,
- $timestamp, $timestamp, $attachment->{bug_id}
- );
-
- $dbh->bz_commit_transaction;
- $updated++;
+ 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, 'text/x-github-pull-request', $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},
+ 'text/x-github-pull-request'
+ );
+ $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
index 8227208c8..7ec92befb 100644
--- a/extensions/BMO/lib/Constants.pm
+++ b/extensions/BMO/lib/Constants.pm
@@ -13,8 +13,8 @@ use warnings;
use base qw(Exporter);
our @EXPORT = qw(
- REQUEST_MAX_ATTACH_LINES
- DEV_ENGAGE_DISCUSS_NEEDINFO
+ REQUEST_MAX_ATTACH_LINES
+ DEV_ENGAGE_DISCUSS_NEEDINFO
);
# Maximum attachment size in lines that will be sent with a
@@ -24,7 +24,7 @@ use constant REQUEST_MAX_ATTACH_LINES => 1000;
# Requestees who need a needinfo flag set for the dev engagement
# discussion bug
use constant DEV_ENGAGE_DISCUSS_NEEDINFO => qw(
- spersing@mozilla.com
+ spersing@mozilla.com
);
1;
diff --git a/extensions/BMO/lib/Data.pm b/extensions/BMO/lib/Data.pm
index 349f88093..a1e010346 100644
--- a/extensions/BMO/lib/Data.pm
+++ b/extensions/BMO/lib/Data.pm
@@ -15,13 +15,13 @@ 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
- %create_bug_formats
- @default_named_queries
- %autodetect_attach_urls );
+ %group_change_notification
+ $cf_setters
+ @always_fileable_groups
+ %group_auto_cc
+ %create_bug_formats
+ @default_named_queries
+ %autodetect_attach_urls );
# Creating an attachment whose contents is a URL matching one of these regexes
# will result in the user being redirected to that URL when viewing the
@@ -43,35 +43,37 @@ my $mozreview_url_re = qr{
}ix;
sub phabricator_url_re {
- my $phab_uri = Bugzilla->params->{phabricator_base_uri} || 'https://example.com';
- return qr/^\Q${phab_uri}\ED\d+$/i;
+ my $phab_uri
+ = Bugzilla->params->{phabricator_base_uri} || 'https://example.com';
+ return qr/^\Q${phab_uri}\ED\d+$/i;
}
our %autodetect_attach_urls = (
- github_pr => {
- title => 'GitHub Pull Request',
- regex => qr#^https://github\.com/[^/]+/[^/]+/pull/\d+/?$#i,
- content_type => 'text/x-github-pull-request',
- can_review => 1,
- },
- reviewboard => {
- title => 'MozReview',
- regex => $mozreview_url_re,
- content_type => 'text/x-review-board-request',
- can_review => 0,
- },
- Phabricator => {
- title => 'Phabricator',
- regex => \&phabricator_url_re,
- content_type => 'text/x-phabricator-request',
- can_review => 1,
- },
- google_docs => {
- title => 'Google Doc',
- regex => qr#^https://docs\.google\.com/(?:document|spreadsheets|presentation)/d/#i,
- content_type => 'text/x-google-doc',
- can_review => 0,
- },
+ github_pr => {
+ title => 'GitHub Pull Request',
+ regex => qr#^https://github\.com/[^/]+/[^/]+/pull/\d+/?$#i,
+ content_type => 'text/x-github-pull-request',
+ can_review => 1,
+ },
+ reviewboard => {
+ title => 'MozReview',
+ regex => $mozreview_url_re,
+ content_type => 'text/x-review-board-request',
+ can_review => 0,
+ },
+ Phabricator => {
+ title => 'Phabricator',
+ regex => \&phabricator_url_re,
+ content_type => 'text/x-phabricator-request',
+ can_review => 1,
+ },
+ google_docs => {
+ title => 'Google Doc',
+ regex =>
+ qr#^https://docs\.google\.com/(?:document|spreadsheets|presentation)/d/#i,
+ content_type => 'text/x-google-doc',
+ can_review => 0,
+ },
);
# Which custom fields are visible in which products and components.
@@ -83,209 +85,184 @@ our %autodetect_attach_urls = (
#
# 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",
- "DCOps",
- ],
- },
- qr/^cf_office$/ => {
- "mozilla.org" => ["Server Operations: Desktop Issues"],
- },
- qr/^cf_crash_signature$/ => {
- "Add-on SDK" => [],
- "addons.mozilla.org" => [],
- "Android Background Services" => [],
- "B2GDroid" => [],
- "Calendar" => [],
- "Composer" => [],
- "Core" => [],
- "DevTools" => [],
- "Directory" => [],
- "External Software Affecting Firefox" => [],
- "Firefox" => [],
- "Firefox for Android" => [],
- "GeckoView" => [],
- "JSS" => [],
- "MailNews Core" => [],
- "Mozilla Labs" => [],
- "Mozilla Localizations" => [],
- "mozilla.org" => [],
- "Cloud Services" => [],
- "NSPR" => [],
- "NSS" => [],
- "Other Applications" => [],
- "Penelope" => [],
- "Release Engineering" => [],
- "Rhino" => [],
- "SeaMonkey" => [],
- "Tamarin" => [],
- "Tech Evangelism" => [],
- "Testing" => [],
- "Thunderbird" => [],
- "Toolkit" => [],
- "WebExtensions" => [],
- },
- qr/^cf_due_date$/ => {
- "bugzilla.mozilla.org" => [],
- "Community Building" => [],
- "Data & BI Services Team" => [],
- "Data Compliance" => [],
- "Developer Engagement" => [],
- "Firefox" => ["Security: Review Requests"],
- "Infrastructure & Operations" => [],
- "Marketing" => [],
- "mozilla.org" => ["Security Assurance: Review Request"],
- "Mozilla Metrics" => [],
- "Mozilla PR" => [],
- "Mozilla Reps" => [],
- },
- qr/^cf_locale$/ => {
- "Mozilla Localizations" => ['Other'],
- "www.mozilla.org" => [],
- },
- qr/^cf_mozilla_project$/ => {
- "Data & BI Services Team" => [],
- },
- qr/^cf_machine_state$/ => {
- "Release Engineering" => ["Buildduty"],
- },
- qr/^cf_rank$/ => {
- "Core" => [],
- "Firefox for Android" => [],
- "Firefox for iOS" => [],
- "Firefox" => [],
- "GeckoView" => [],
- "Hello (Loop)" => [],
- "Cloud Services" => [],
- "Tech Evangelism" => [],
- "Toolkit" => [],
- },
- qr/^cf_has_regression_range$/ => {
- "Core" => [],
- "Firefox for Android" => [],
- "Firefox for iOS" => [],
- "Firefox" => [],
- "GeckoView" => [],
- "Toolkit" => [],
- },
- qr/^cf_has_str$/ => {
- "Core" => [],
- "Firefox for Android" => [],
- "Firefox for iOS" => [],
- "Firefox" => [],
- "GeckoView" => [],
- "Toolkit" => [],
- },
- qr/^cf_cab_review$/ => {
- "Infrastructure & Operations Graveyard" => [],
- "Infrastructure & Operations" => [],
- "Data & BI Services Team" => [],
- }
+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", "DCOps",],
+ },
+ qr/^cf_office$/ => {"mozilla.org" => ["Server Operations: Desktop Issues"],},
+ qr/^cf_crash_signature$/ => {
+ "Add-on SDK" => [],
+ "addons.mozilla.org" => [],
+ "Android Background Services" => [],
+ "B2GDroid" => [],
+ "Calendar" => [],
+ "Composer" => [],
+ "Core" => [],
+ "DevTools" => [],
+ "Directory" => [],
+ "External Software Affecting Firefox" => [],
+ "Firefox" => [],
+ "Firefox for Android" => [],
+ "GeckoView" => [],
+ "JSS" => [],
+ "MailNews Core" => [],
+ "Mozilla Labs" => [],
+ "Mozilla Localizations" => [],
+ "mozilla.org" => [],
+ "Cloud Services" => [],
+ "NSPR" => [],
+ "NSS" => [],
+ "Other Applications" => [],
+ "Penelope" => [],
+ "Release Engineering" => [],
+ "Rhino" => [],
+ "SeaMonkey" => [],
+ "Tamarin" => [],
+ "Tech Evangelism" => [],
+ "Testing" => [],
+ "Thunderbird" => [],
+ "Toolkit" => [],
+ "WebExtensions" => [],
+ },
+ qr/^cf_due_date$/ => {
+ "bugzilla.mozilla.org" => [],
+ "Community Building" => [],
+ "Data & BI Services Team" => [],
+ "Data Compliance" => [],
+ "Developer Engagement" => [],
+ "Firefox" => ["Security: Review Requests"],
+ "Infrastructure & Operations" => [],
+ "Marketing" => [],
+ "mozilla.org" => ["Security Assurance: Review Request"],
+ "Mozilla Metrics" => [],
+ "Mozilla PR" => [],
+ "Mozilla Reps" => [],
+ },
+ qr/^cf_locale$/ =>
+ {"Mozilla Localizations" => ['Other'], "www.mozilla.org" => [],},
+ qr/^cf_mozilla_project$/ => {"Data & BI Services Team" => [],},
+ qr/^cf_machine_state$/ => {"Release Engineering" => ["Buildduty"],},
+ qr/^cf_rank$/ => {
+ "Core" => [],
+ "Firefox for Android" => [],
+ "Firefox for iOS" => [],
+ "Firefox" => [],
+ "GeckoView" => [],
+ "Hello (Loop)" => [],
+ "Cloud Services" => [],
+ "Tech Evangelism" => [],
+ "Toolkit" => [],
+ },
+ qr/^cf_has_regression_range$/ => {
+ "Core" => [],
+ "Firefox for Android" => [],
+ "Firefox for iOS" => [],
+ "Firefox" => [],
+ "GeckoView" => [],
+ "Toolkit" => [],
+ },
+ qr/^cf_has_str$/ => {
+ "Core" => [],
+ "Firefox for Android" => [],
+ "Firefox for iOS" => [],
+ "Firefox" => [],
+ "GeckoView" => [],
+ "Toolkit" => [],
+ },
+ qr/^cf_cab_review$/ => {
+ "Infrastructure & Operations Graveyard" => [],
+ "Infrastructure & Operations" => [],
+ "Data & BI Services Team" => [],
+ }
);
# Who to CC on particular bugmails when certain groups are added or removed.
our %group_change_notification = (
- 'addons-security' => ['amo-editors@mozilla.org'],
- 'b2g-core-security' => ['security@mozilla.org'],
- 'bugzilla-security' => ['security@bugzilla.org'],
- 'client-services-security' => ['amo-admins@mozilla.org', 'web-security@mozilla.org'],
- 'cloud-services-security' => ['web-security@mozilla.org'],
- 'core-security' => ['security@mozilla.org'],
- 'crypto-core-security' => ['security@mozilla.org'],
- 'dom-core-security' => ['security@mozilla.org'],
- 'firefox-core-security' => ['security@mozilla.org'],
- 'gfx-core-security' => ['security@mozilla.org'],
- 'javascript-core-security' => ['security@mozilla.org'],
- 'layout-core-security' => ['security@mozilla.org'],
- 'mail-core-security' => ['security@mozilla.org'],
- 'media-core-security' => ['security@mozilla.org'],
- 'network-core-security' => ['security@mozilla.org'],
- 'core-security-release' => ['security@mozilla.org'],
- 'tamarin-security' => ['tamarinsecurity@adobe.com'],
- 'toolkit-core-security' => ['security@mozilla.org'],
- 'websites-security' => ['web-security@mozilla.org'],
- 'webtools-security' => ['web-security@mozilla.org'],
+ 'addons-security' => ['amo-editors@mozilla.org'],
+ 'b2g-core-security' => ['security@mozilla.org'],
+ 'bugzilla-security' => ['security@bugzilla.org'],
+ 'client-services-security' =>
+ ['amo-admins@mozilla.org', 'web-security@mozilla.org'],
+ 'cloud-services-security' => ['web-security@mozilla.org'],
+ 'core-security' => ['security@mozilla.org'],
+ 'crypto-core-security' => ['security@mozilla.org'],
+ 'dom-core-security' => ['security@mozilla.org'],
+ 'firefox-core-security' => ['security@mozilla.org'],
+ 'gfx-core-security' => ['security@mozilla.org'],
+ 'javascript-core-security' => ['security@mozilla.org'],
+ 'layout-core-security' => ['security@mozilla.org'],
+ 'mail-core-security' => ['security@mozilla.org'],
+ 'media-core-security' => ['security@mozilla.org'],
+ 'network-core-security' => ['security@mozilla.org'],
+ 'core-security-release' => ['security@mozilla.org'],
+ 'tamarin-security' => ['tamarinsecurity@adobe.com'],
+ 'toolkit-core-security' => ['security@mozilla.org'],
+ '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' ],
- 'cf_rank' => [ 'rank-setters' ],
-};
+our $cf_setters
+ = {'cf_colo_site' => ['infra', 'build'], 'cf_rank' => ['rank-setters'],};
# 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
+ 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
);
# 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'],
- },
+ '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 = (
- 'Data Compliance' => {
- 'format' => 'data-compliance',
- 'include' => 'everyone',
- },
- 'developer.mozilla.org' => {
- 'format' => 'mdn',
- 'include' => 'everyone',
- },
- 'Legal' => {
- 'format' => 'legal',
- 'include' => 'everyone',
- },
- 'Recruiting' => {
- 'format' => 'recruiting',
- 'include' => 'everyone',
- },
- 'Internet Public Policy' => {
- 'format' => 'ipp',
- 'include' => 'everyone',
- },
+ 'Data Compliance' => {'format' => 'data-compliance', 'include' => 'everyone',},
+ 'developer.mozilla.org' => {'format' => 'mdn', 'include' => 'everyone',},
+ 'Legal' => {'format' => 'legal', 'include' => 'everyone',},
+ 'Recruiting' => {'format' => 'recruiting', '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',
- },
+ {
+ 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
index f84835ddd..5b5395619 100644
--- a/extensions/BMO/lib/FakeBug.pm
+++ b/extensions/BMO/lib/FakeBug.pm
@@ -12,32 +12,32 @@ use Bugzilla::Bug;
our $AUTOLOAD;
sub new {
- my $class = shift;
- my $self = shift;
- bless $self, $class;
- return $self;
+ 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;
+ 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, @_)
+ my $self = shift;
+ return Bugzilla::Bug::check_can_change_field($self, @_);
}
sub _changes_everconfirmed {
- my $self = shift;
- return Bugzilla::Bug::_changes_everconfirmed($self, @_)
+ my $self = shift;
+ return Bugzilla::Bug::_changes_everconfirmed($self, @_);
}
sub everconfirmed {
- my $self = shift;
- return ($self->{'status'} == 'UNCONFIRMED') ? 0 : 1;
+ my $self = shift;
+ return ($self->{'status'} == 'UNCONFIRMED') ? 0 : 1;
}
1;
diff --git a/extensions/BMO/lib/Reports/Groups.pm b/extensions/BMO/lib/Reports/Groups.pm
index ce7df767c..7b395aca9 100644
--- a/extensions/BMO/lib/Reports/Groups.pm
+++ b/extensions/BMO/lib/Reports/Groups.pm
@@ -19,25 +19,24 @@ use Bugzilla::Util qw(trim datetime_from);
use JSON qw(encode_json);
sub admins_report {
- my ($vars) = @_;
- my $dbh = Bugzilla->dbh;
- my $user = Bugzilla->user;
+ my ($vars) = @_;
+ my $dbh = Bugzilla->dbh;
+ my $user = Bugzilla->user;
- ($user->in_group('editbugs'))
- || ThrowUserError('auth_failure', { group => 'editbugs',
- action => 'run',
- object => 'group_admins' });
+ ($user->in_group('editbugs'))
+ || ThrowUserError('auth_failure',
+ {group => 'editbugs', action => 'run', object => 'group_admins'});
- my @grouplist =
- ($user->in_group('editusers') || $user->in_group('infrasec'))
- ? map { lc($_->name) } Bugzilla::Group->get_all
- : _get_permitted_membership_groups();
+ my @grouplist
+ = ($user->in_group('editusers') || $user->in_group('infrasec'))
+ ? map { lc($_->name) } Bugzilla::Group->get_all
+ : _get_permitted_membership_groups();
- my $groups = join(',', map { $dbh->quote($_) } @grouplist);
+ my $groups = join(',', map { $dbh->quote($_) } @grouplist);
- my $query = "
- SELECT groups.id, " .
- $dbh->sql_group_concat('profiles.userid', "','", 1) . "
+ my $query = "
+ SELECT groups.id, "
+ . $dbh->sql_group_concat('profiles.userid', "','", 1) . "
FROM groups
LEFT JOIN user_group_map
ON user_group_map.group_id = groups.id
@@ -49,271 +48,275 @@ sub admins_report {
AND groups.name IN ($groups)
GROUP BY groups.name";
- my @groups;
- foreach my $row (@{ $dbh->selectall_arrayref($query) }) {
- my $group = Bugzilla::Group->new({ id => shift @$row, cache => 1});
- my @admins;
- if (my $admin_ids = shift @$row) {
- foreach my $uid (split(/,/, $admin_ids)) {
- push(@admins, Bugzilla::User->new({ id => $uid, cache => 1 }));
- }
- }
- push(@groups, { name => $group->name,
- description => $group->description,
- owner => $group->owner,
- admins => \@admins });
+ my @groups;
+ foreach my $row (@{$dbh->selectall_arrayref($query)}) {
+ my $group = Bugzilla::Group->new({id => shift @$row, cache => 1});
+ my @admins;
+ if (my $admin_ids = shift @$row) {
+ foreach my $uid (split(/,/, $admin_ids)) {
+ push(@admins, Bugzilla::User->new({id => $uid, cache => 1}));
+ }
}
+ push(
+ @groups,
+ {
+ name => $group->name,
+ description => $group->description,
+ owner => $group->owner,
+ admins => \@admins
+ }
+ );
+ }
- $vars->{'groups'} = \@groups;
+ $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;
+ 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 ];
+ 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));
+ 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
+ # 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
+ 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);
+ WHERE user_id = ? AND isbless = 0}, undef, $u->id
+ );
- my $rows = $dbh->selectall_arrayref(
- "SELECT DISTINCT grantor_id, member_id
+ my $rows = $dbh->selectall_arrayref(
+ "SELECT DISTINCT grantor_id, member_id
FROM group_group_map
- WHERE grant_type = " . GROUP_MEMBERSHIP);
+ 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 %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;
+ my %checked_groups;
+ my %direct_groups;
+ my %indirect_groups;
+ my %groups;
- foreach my $member_id (@$groups_to_check) {
- $direct_groups{$member_id} = 1;
- }
+ 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;
- }
+ 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,
- };
+ 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 @users, {
- user => $u,
- groups => \@groups,
- };
+ }
+ push @groups, {name => $group->name, desc => $group->description, via => $via,};
}
- $vars->{'who'} = $who;
- $vars->{'users'} = \@users;
+ push @users, {user => $u, groups => \@groups,};
+ }
+
+ $vars->{'who'} = $who;
+ $vars->{'users'} = \@users;
}
sub members_report {
- my ($page, $vars) = @_;
- my $dbh = Bugzilla->dbh;
- my $user = Bugzilla->user;
- my $cgi = Bugzilla->cgi;
-
- ($user->in_group('editbugs'))
- || ThrowUserError('auth_failure', { group => 'editbugs',
- action => 'run',
- object => 'group_admins' });
-
- my $privileged = $user->in_group('editusers') || $user->in_group('infrasec');
- $vars->{privileged} = $privileged;
-
- my @grouplist = $privileged
- ? map { lc($_->name) } Bugzilla::Group->get_all
- : _get_permitted_membership_groups();
-
- 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)$/ }
- @grouplist;
- 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_obj;
-
- $vars->{'privileged'} = 1 if ($group_obj->owner && $group_obj->owner->id == $user->id);
-
- my @types;
- my $members = $group_obj->members_complete();
- foreach my $name (sort keys %$members) {
- push @types, {
- name => ($name eq '_direct' ? 'direct' : $name),
- members => _filter_userlist($members->{$name}),
+ my ($page, $vars) = @_;
+ my $dbh = Bugzilla->dbh;
+ my $user = Bugzilla->user;
+ my $cgi = Bugzilla->cgi;
+
+ ($user->in_group('editbugs'))
+ || ThrowUserError('auth_failure',
+ {group => 'editbugs', action => 'run', object => 'group_admins'});
+
+ my $privileged = $user->in_group('editusers') || $user->in_group('infrasec');
+ $vars->{privileged} = $privileged;
+
+ my @grouplist
+ = $privileged
+ ? map { lc($_->name) } Bugzilla::Group->get_all
+ : _get_permitted_membership_groups();
+
+ 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)$/ }
+ @grouplist;
+ 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_obj;
+
+ $vars->{'privileged'} = 1
+ if ($group_obj->owner && $group_obj->owner->id == $user->id);
+
+ my @types;
+ my $members = $group_obj->members_complete();
+ foreach my $name (sort keys %$members) {
+ push @types,
+ {
+ name => ($name eq '_direct' ? 'direct' : $name),
+ members => _filter_userlist($members->{$name}),
+ };
+ }
+
+ # 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 ($page eq 'group_members.json') {
+ my %users;
+ foreach my $rh (@types) {
+ foreach my $member (@{$rh->{members}}) {
+ my $login = $member->login;
+ if (exists $users{$login}) {
+ push @{$users{$login}->{groups}}, $rh->{name} if $privileged;
}
- }
-
- # 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 ($page eq 'group_members.json') {
- my %users;
- foreach my $rh (@types) {
- foreach my $member (@{ $rh->{members} }) {
- my $login = $member->login;
- if (exists $users{$login}) {
- push @{ $users{$login}->{groups} }, $rh->{name} if $privileged;
- }
- else {
- my $rh_user = {
- login => $login,
- membership => $rh->{name} eq 'direct' ? 'direct' : 'indirect',
- rh_name => $rh->{name},
- };
- if ($privileged) {
- $rh_user->{group} = $rh->{name};
- $rh_user->{groups} = [ $rh->{name} ];
- $rh_user->{lastseeon} = $member->last_seen_date;
- $rh_user->{mfa} = $member->mfa;
- $rh_user->{api_key_only} = $member->settings->{api_key_only}->{value} eq 'on'
- ? JSON::true : JSON::false;
- }
- $users{$login} = $rh_user;
- }
- }
+ else {
+ my $rh_user = {
+ login => $login,
+ membership => $rh->{name} eq 'direct' ? 'direct' : 'indirect',
+ rh_name => $rh->{name},
+ };
+ if ($privileged) {
+ $rh_user->{group} = $rh->{name};
+ $rh_user->{groups} = [$rh->{name}];
+ $rh_user->{lastseeon} = $member->last_seen_date;
+ $rh_user->{mfa} = $member->mfa;
+ $rh_user->{api_key_only}
+ = $member->settings->{api_key_only}->{value} eq 'on'
+ ? JSON::true
+ : JSON::false;
+ }
+ $users{$login} = $rh_user;
}
- $vars->{types_json} = JSON->new->pretty->canonical->utf8->encode([ values %users ]);
+ }
}
- else {
- my %users;
- foreach my $rh (@types) {
- foreach my $member (@{ $rh->{members} }) {
- $users{$member->login} = 1 unless exists $users{$member->login};
- }
- }
- $vars->{types} = \@types;
- $vars->{count} = scalar(keys %users);
+ $vars->{types_json}
+ = JSON->new->pretty->canonical->utf8->encode([values %users]);
+ }
+ else {
+ my %users;
+ foreach my $rh (@types) {
+ foreach my $member (@{$rh->{members}}) {
+ $users{$member->login} = 1 unless exists $users{$member->login};
+ }
}
+ $vars->{types} = \@types;
+ $vars->{count} = scalar(keys %users);
+ }
}
sub _filter_userlist {
- my ($list, $include_disabled) = @_;
- $list = [ grep { $_->is_enabled } @$list ] unless $include_disabled;
- my $now = DateTime->now();
- my $never = DateTime->from_epoch( epoch => 0 );
- foreach my $user (@$list) {
- my $last_seen = $user->last_seen_date ? datetime_from($user->last_seen_date) : $never;
- $user->{last_seen_days} = sprintf(
- '%.0f',
- $now->subtract_datetime_absolute($last_seen)->delta_seconds / (28 * 60 * 60));
- }
- return [ sort { lc($a->identity) cmp lc($b->identity) } @$list ];
+ my ($list, $include_disabled) = @_;
+ $list = [grep { $_->is_enabled } @$list] unless $include_disabled;
+ my $now = DateTime->now();
+ my $never = DateTime->from_epoch(epoch => 0);
+ foreach my $user (@$list) {
+ my $last_seen
+ = $user->last_seen_date ? datetime_from($user->last_seen_date) : $never;
+ $user->{last_seen_days} = sprintf('%.0f',
+ $now->subtract_datetime_absolute($last_seen)->delta_seconds / (28 * 60 * 60));
+ }
+ return [sort { lc($a->identity) cmp lc($b->identity) } @$list];
}
# Groups that any user with editbugs can see the membership or admin lists for.
# Transparency FTW.
sub _get_permitted_membership_groups {
- my $user = Bugzilla->user;
-
- # Default publicly viewable groups
- my %default_public_groups = map { $_ => 1 } qw(
- bugzilla-approvers
- bugzilla-reviewers
- can_restrict_comments
- community-it-team
- mozilla-employee-confidential
- mozilla-foundation-confidential
- mozilla-reps
- qa-approvers
- );
-
- # We add the group to the permitted list if:
- # 1. it is a drivers group - this gives us a little
- # future-proofing
- # 2. it is a one of the default public groups
- # 3. the user is the group's owner
- # 4. or the user can bless others into the group
- my @permitted_groups;
- foreach my $group (Bugzilla::Group->get_all) {
- my $name = $group->name;
- if ($name =~ /-drivers$/
- || exists $default_public_groups{$name}
- || ($group->owner && $group->owner->id == $user->id)
- || $user->can_bless($group->id))
- {
- push(@permitted_groups, $name);
- }
+ my $user = Bugzilla->user;
+
+ # Default publicly viewable groups
+ my %default_public_groups = map { $_ => 1 } qw(
+ bugzilla-approvers
+ bugzilla-reviewers
+ can_restrict_comments
+ community-it-team
+ mozilla-employee-confidential
+ mozilla-foundation-confidential
+ mozilla-reps
+ qa-approvers
+ );
+
+ # We add the group to the permitted list if:
+ # 1. it is a drivers group - this gives us a little
+ # future-proofing
+ # 2. it is a one of the default public groups
+ # 3. the user is the group's owner
+ # 4. or the user can bless others into the group
+ my @permitted_groups;
+ foreach my $group (Bugzilla::Group->get_all) {
+ my $name = $group->name;
+ if ( $name =~ /-drivers$/
+ || exists $default_public_groups{$name}
+ || ($group->owner && $group->owner->id == $user->id)
+ || $user->can_bless($group->id))
+ {
+ push(@permitted_groups, $name);
}
+ }
- return @permitted_groups;
+ return @permitted_groups;
}
1;
diff --git a/extensions/BMO/lib/Reports/Internship.pm b/extensions/BMO/lib/Reports/Internship.pm
index 2dfa583a6..f9ad1a578 100644
--- a/extensions/BMO/lib/Reports/Internship.pm
+++ b/extensions/BMO/lib/Reports/Internship.pm
@@ -17,33 +17,30 @@ use Bugzilla::Product;
use Bugzilla::Component;
sub report {
- my ($vars) = @_;
- my $user = Bugzilla->user;
-
- $user->in_group('hr')
- || ThrowUserError('auth_failure', { group => 'hr',
- action => 'run',
- object => 'internship_dashboard' });
-
- my $product = Bugzilla::Product->check({ name => 'Recruiting', cache => 1 });
- my $component = Bugzilla::Component->new({ product => $product, name => 'Intern', cache => 1 });
-
- # find all open internship bugs
- my $bugs = Bugzilla::Bug->match({
- product_id => $product->id,
- component_id => $component->id,
- resolution => '',
- });
-
- # filter bugs based on visibility and re-bless
- $user->visible_bugs($bugs);
- $bugs = [
- map { bless($_, 'InternshipBug') }
- grep { $user->can_see_bug($_->id) }
- @$bugs
- ];
-
- $vars->{bugs} = $bugs;
+ my ($vars) = @_;
+ my $user = Bugzilla->user;
+
+ $user->in_group('hr')
+ || ThrowUserError('auth_failure',
+ {group => 'hr', action => 'run', object => 'internship_dashboard'});
+
+ my $product = Bugzilla::Product->check({name => 'Recruiting', cache => 1});
+ my $component = Bugzilla::Component->new(
+ {product => $product, name => 'Intern', cache => 1});
+
+ # find all open internship bugs
+ my $bugs = Bugzilla::Bug->match({
+ product_id => $product->id,
+ component_id => $component->id,
+ resolution => '',
+ });
+
+ # filter bugs based on visibility and re-bless
+ $user->visible_bugs($bugs);
+ $bugs = [map { bless($_, 'InternshipBug') }
+ grep { $user->can_see_bug($_->id) } @$bugs];
+
+ $vars->{bugs} = $bugs;
}
1;
@@ -58,64 +55,62 @@ use Bugzilla::Comment;
use Bugzilla::Util qw(trim);
sub _extract {
- my ($self) = @_;
- return if exists $self->{internship_data};
- $self->{internship_data} = {};
-
- # we only need the first comment
- my $comment = Bugzilla::Comment->match({
- bug_id => $self->id,
- LIMIT => 1,
- })->[0]->body;
-
- # extract just what we need
- # changing the comment will break this
-
- if ($comment =~ /Hiring Manager:\s+(.+)\nTeam:\n/s) {
- $self->{internship_data}->{hiring_manager} = trim($1);
- }
- if ($comment =~ /\nVP Authority:\s+(.+)\nProduct Line:\n/s) {
- $self->{internship_data}->{scvp} = trim($1);
- }
- if ($comment =~ /\nProduct Line:\s+(.+)\nLevel 1/s) {
- $self->{internship_data}->{product_line} = trim($1);
- }
- if ($comment =~ /\nBusiness Need:\s+(.+)\nPotential Project:\n/s) {
- $self->{internship_data}->{business_need} = trim($1);
- }
- if ($comment =~ /\nName:\s+(.+)$/s) {
- $self->{internship_data}->{intern_name} = trim($1);
- }
+ my ($self) = @_;
+ return if exists $self->{internship_data};
+ $self->{internship_data} = {};
+
+ # we only need the first comment
+ my $comment
+ = Bugzilla::Comment->match({bug_id => $self->id, LIMIT => 1,})->[0]->body;
+
+ # extract just what we need
+ # changing the comment will break this
+
+ if ($comment =~ /Hiring Manager:\s+(.+)\nTeam:\n/s) {
+ $self->{internship_data}->{hiring_manager} = trim($1);
+ }
+ if ($comment =~ /\nVP Authority:\s+(.+)\nProduct Line:\n/s) {
+ $self->{internship_data}->{scvp} = trim($1);
+ }
+ if ($comment =~ /\nProduct Line:\s+(.+)\nLevel 1/s) {
+ $self->{internship_data}->{product_line} = trim($1);
+ }
+ if ($comment =~ /\nBusiness Need:\s+(.+)\nPotential Project:\n/s) {
+ $self->{internship_data}->{business_need} = trim($1);
+ }
+ if ($comment =~ /\nName:\s+(.+)$/s) {
+ $self->{internship_data}->{intern_name} = trim($1);
+ }
}
sub hiring_manager {
- my ($self) = @_;
- $self->_extract();
- return $self->{internship_data}->{hiring_manager};
+ my ($self) = @_;
+ $self->_extract();
+ return $self->{internship_data}->{hiring_manager};
}
sub scvp {
- my ($self) = @_;
- $self->_extract();
- return $self->{internship_data}->{scvp};
+ my ($self) = @_;
+ $self->_extract();
+ return $self->{internship_data}->{scvp};
}
sub business_need {
- my ($self) = @_;
- $self->_extract();
- return $self->{internship_data}->{business_need};
+ my ($self) = @_;
+ $self->_extract();
+ return $self->{internship_data}->{business_need};
}
sub product_line {
- my ($self) = @_;
- $self->_extract();
- return $self->{internship_data}->{product_line};
+ my ($self) = @_;
+ $self->_extract();
+ return $self->{internship_data}->{product_line};
}
sub intern_name {
- my ($self) = @_;
- $self->_extract();
- return $self->{internship_data}->{intern_name};
+ my ($self) = @_;
+ $self->_extract();
+ return $self->{internship_data}->{intern_name};
}
1;
diff --git a/extensions/BMO/lib/Reports/ProductSecurity.pm b/extensions/BMO/lib/Reports/ProductSecurity.pm
index e7ccda171..fb773cd93 100644
--- a/extensions/BMO/lib/Reports/ProductSecurity.pm
+++ b/extensions/BMO/lib/Reports/ProductSecurity.pm
@@ -16,54 +16,54 @@ use Bugzilla::Error;
use Bugzilla::Product;
sub report {
- my ($vars) = @_;
- my $user = Bugzilla->user;
+ my ($vars) = @_;
+ my $user = Bugzilla->user;
- ($user->in_group('admin') || $user->in_group('infrasec'))
- || ThrowUserError('auth_failure', { group => 'admin',
- action => 'run',
- object => 'product_security' });
+ ($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 $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 $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},
- };
+ 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});
- }
- }
+ 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');
+ $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;
+ 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 '';
+ 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/Recruiting.pm b/extensions/BMO/lib/Reports/Recruiting.pm
index 39eb8327d..c35b0cbff 100644
--- a/extensions/BMO/lib/Reports/Recruiting.pm
+++ b/extensions/BMO/lib/Reports/Recruiting.pm
@@ -17,33 +17,30 @@ use Bugzilla::Product;
use Bugzilla::Component;
sub report {
- my ($vars) = @_;
- my $user = Bugzilla->user;
-
- $user->in_group('hr')
- || ThrowUserError('auth_failure', { group => 'hr',
- action => 'run',
- object => 'recruiting_dashboard' });
-
- my $product = Bugzilla::Product->check({ name => 'Recruiting', cache => 1 });
- my $component = Bugzilla::Component->new({ product => $product, name => 'General', cache => 1 });
-
- # find all open recruiting bugs
- my $bugs = Bugzilla::Bug->match({
- product_id => $product->id,
- component_id => $component->id,
- resolution => '',
- });
-
- # filter bugs based on visibility and re-bless
- $user->visible_bugs($bugs);
- $bugs = [
- map { bless($_, 'RecruitingBug') }
- grep { $user->can_see_bug($_->id) }
- @$bugs
- ];
-
- $vars->{bugs} = $bugs;
+ my ($vars) = @_;
+ my $user = Bugzilla->user;
+
+ $user->in_group('hr')
+ || ThrowUserError('auth_failure',
+ {group => 'hr', action => 'run', object => 'recruiting_dashboard'});
+
+ my $product = Bugzilla::Product->check({name => 'Recruiting', cache => 1});
+ my $component = Bugzilla::Component->new(
+ {product => $product, name => 'General', cache => 1});
+
+ # find all open recruiting bugs
+ my $bugs = Bugzilla::Bug->match({
+ product_id => $product->id,
+ component_id => $component->id,
+ resolution => '',
+ });
+
+ # filter bugs based on visibility and re-bless
+ $user->visible_bugs($bugs);
+ $bugs = [map { bless($_, 'RecruitingBug') }
+ grep { $user->can_see_bug($_->id) } @$bugs];
+
+ $vars->{bugs} = $bugs;
}
1;
@@ -58,55 +55,56 @@ use Bugzilla::Comment;
use Bugzilla::Util qw(trim);
sub _extract {
- my ($self) = @_;
- return if exists $self->{recruitment_data};
- $self->{recruitment_data} = {};
-
- # we only need the first comment
- my $comment = Bugzilla::Comment->match({
- bug_id => $self->id,
- LIMIT => 1,
- })->[0]->body;
-
- # extract just what we need
- # changing the comment will break this
-
- if ($comment =~ /\nHiring Manager:\s+(.+)VP Authority:\n/s) {
- $self->{recruitment_data}->{hiring_manager} = trim($1);
- }
- if ($comment =~ /\nVP Authority:\s+(.+)HRBP:\n/s) {
- $self->{recruitment_data}->{scvp} = trim($1);
- }
- if ($comment =~ /\nWhat part of your strategic plan does this role impact\?\s+(.+)Why is this critical for success\?\n/s) {
- $self->{recruitment_data}->{strategic_plan} = trim($1);
- }
- if ($comment =~ /\nWhy is this critical for success\?\s+(.+)$/s) {
- $self->{recruitment_data}->{why_critical} = trim($1);
- }
+ my ($self) = @_;
+ return if exists $self->{recruitment_data};
+ $self->{recruitment_data} = {};
+
+ # we only need the first comment
+ my $comment
+ = Bugzilla::Comment->match({bug_id => $self->id, LIMIT => 1,})->[0]->body;
+
+ # extract just what we need
+ # changing the comment will break this
+
+ if ($comment =~ /\nHiring Manager:\s+(.+)VP Authority:\n/s) {
+ $self->{recruitment_data}->{hiring_manager} = trim($1);
+ }
+ if ($comment =~ /\nVP Authority:\s+(.+)HRBP:\n/s) {
+ $self->{recruitment_data}->{scvp} = trim($1);
+ }
+ if ($comment
+ =~ /\nWhat part of your strategic plan does this role impact\?\s+(.+)Why is this critical for success\?\n/s
+ )
+ {
+ $self->{recruitment_data}->{strategic_plan} = trim($1);
+ }
+ if ($comment =~ /\nWhy is this critical for success\?\s+(.+)$/s) {
+ $self->{recruitment_data}->{why_critical} = trim($1);
+ }
}
sub hiring_manager {
- my ($self) = @_;
- $self->_extract();
- return $self->{recruitment_data}->{hiring_manager};
+ my ($self) = @_;
+ $self->_extract();
+ return $self->{recruitment_data}->{hiring_manager};
}
sub scvp {
- my ($self) = @_;
- $self->_extract();
- return $self->{recruitment_data}->{scvp};
+ my ($self) = @_;
+ $self->_extract();
+ return $self->{recruitment_data}->{scvp};
}
sub strategic_plan {
- my ($self) = @_;
- $self->_extract();
- return $self->{recruitment_data}->{strategic_plan};
+ my ($self) = @_;
+ $self->_extract();
+ return $self->{recruitment_data}->{strategic_plan};
}
sub why_critical {
- my ($self) = @_;
- $self->_extract();
- return $self->{recruitment_data}->{why_critical};
+ my ($self) = @_;
+ $self->_extract();
+ return $self->{recruitment_data}->{why_critical};
}
1;
diff --git a/extensions/BMO/lib/Reports/ReleaseTracking.pm b/extensions/BMO/lib/Reports/ReleaseTracking.pm
index 9fba1e14b..38a07aee7 100644
--- a/extensions/BMO/lib/Reports/ReleaseTracking.pm
+++ b/extensions/BMO/lib/Reports/ReleaseTracking.pm
@@ -21,496 +21,381 @@ use JSON qw(-convert_blessed_universally);
use List::MoreUtils qw(uniq);
use constant DATE_RANGES => [
- {
- value => '20160126-20160307',
- label => '2016-01-26 and 2016-03-07'
- },
- {
- value => '20151215-20160125',
- label => '2015-12-15 and 2016-01-25'
- },
- {
- value => '20151103-20151214',
- label => '2015-11-03 and 2015-12-14'
- },
- {
- value => '20150922-20151102',
- label => '2015-09-22 and 2015-11-02'
- },
- {
- value => '20150811-20150921',
- label => '2015-08-11 and 2015-09-21'
- },
- {
- value => '20150630-20150810',
- label => '2015-06-30 and 2015-08-10'
- },
- {
- value => '20150512-20150629',
- label => '2015-05-12 and 2015-06-29'
- },
- {
- value => '20150331-20150511',
- label => '2015-03-31 and 2015-05-11'
- },
- {
- value => '20150224-20150330',
- label => '2015-02-24 and 2015-03-30'
- },
- {
- value => '20150113-20150223',
- label => '2015-01-13 and 2015-02-23'
- },
- {
- value => '20141111-20141222',
- label => '2014-11-11 and 2014-12-22'
- },
- {
- value => '20140930-20141110',
- label => '2014-09-30 and 2014-11-10'
- },
- {
- value => '20140819-20140929',
- label => '2014-08-19 and 2014-09-29'
- },
- {
- value => '20140708-20140818',
- label => '2014-07-08 and 2014-08-18'
- },
- {
- value => '20140527-20140707',
- label => '2014-05-27 and 2014-07-07'
- },
- {
- value => '20140415-20140526',
- label => '2014-04-15 and 2014-05-26'
- },
- {
- value => '20140304-20140414',
- label => '2014-03-04 and 2014-04-14'
- },
- {
- value => '20140121-20140303',
- label => '2014-01-21 and 2014-03-03'
- },
- {
- value => '20131210-20140120',
- label => '2013-12-10 and 2014-01-20'
- },
- {
- value => '20131029-20131209',
- label => '2013-10-29 and 2013-12-09'
- },
- {
- value => '20130917-20131028',
- label => '2013-09-17 and 2013-10-28'
- },
- {
- value => '20130806-20130916',
- label => '2013-08-06 and 2013-09-16'
- },
- {
- value => '20130625-20130805',
- label => '2013-06-25 and 2013-08-05'
- },
- {
- value => '20130514-20130624',
- label => '2013-05-14 and 2013-06-24'
- },
- {
- value => '20130402-20130513',
- label => '2013-04-02 and 2013-05-13'
- },
- {
- value => '20130219-20130401',
- label => '2013-02-19 and 2013-04-01'
- },
- {
- value => '20130108-20130218',
- label => '2013-01-08 and 2013-02-18'
- },
- {
- value => '20121120-20130107',
- label => '2012-11-20 and 2013-01-07'
- },
- {
- value => '20121009-20121119',
- label => '2012-10-09 and 2012-11-19'
- },
- {
- value => '20120828-20121008',
- label => '2012-08-28 and 2012-10-08'
- },
- {
- value => '20120717-20120827',
- label => '2012-07-17 and 2012-08-27'
- },
- {
- value => '20120605-20120716',
- label => '2012-06-05 and 2012-07-16'
- },
- {
- value => '20120424-20120604',
- label => '2012-04-24 and 2012-06-04'
- },
- {
- value => '20120313-20120423',
- label => '2012-03-13 and 2012-04-23'
- },
- {
- value => '20120131-20120312',
- label => '2012-01-31 and 2012-03-12'
- },
- {
- value => '20111220-20120130',
- label => '2011-12-20 and 2012-01-30'
- },
- {
- value => '20111108-20111219',
- label => '2011-11-08 and 2011-12-19'
- },
- {
- value => '20110927-20111107',
- label => '2011-09-27 and 2011-11-07'
- },
- {
- value => '20110816-20110926',
- label => '2011-08-16 and 2011-09-26'
- },
- {
- value => '*',
- label => 'Anytime'
- }
+ {value => '20160126-20160307', label => '2016-01-26 and 2016-03-07'},
+ {value => '20151215-20160125', label => '2015-12-15 and 2016-01-25'},
+ {value => '20151103-20151214', label => '2015-11-03 and 2015-12-14'},
+ {value => '20150922-20151102', label => '2015-09-22 and 2015-11-02'},
+ {value => '20150811-20150921', label => '2015-08-11 and 2015-09-21'},
+ {value => '20150630-20150810', label => '2015-06-30 and 2015-08-10'},
+ {value => '20150512-20150629', label => '2015-05-12 and 2015-06-29'},
+ {value => '20150331-20150511', label => '2015-03-31 and 2015-05-11'},
+ {value => '20150224-20150330', label => '2015-02-24 and 2015-03-30'},
+ {value => '20150113-20150223', label => '2015-01-13 and 2015-02-23'},
+ {value => '20141111-20141222', label => '2014-11-11 and 2014-12-22'},
+ {value => '20140930-20141110', label => '2014-09-30 and 2014-11-10'},
+ {value => '20140819-20140929', label => '2014-08-19 and 2014-09-29'},
+ {value => '20140708-20140818', label => '2014-07-08 and 2014-08-18'},
+ {value => '20140527-20140707', label => '2014-05-27 and 2014-07-07'},
+ {value => '20140415-20140526', label => '2014-04-15 and 2014-05-26'},
+ {value => '20140304-20140414', label => '2014-03-04 and 2014-04-14'},
+ {value => '20140121-20140303', label => '2014-01-21 and 2014-03-03'},
+ {value => '20131210-20140120', label => '2013-12-10 and 2014-01-20'},
+ {value => '20131029-20131209', label => '2013-10-29 and 2013-12-09'},
+ {value => '20130917-20131028', label => '2013-09-17 and 2013-10-28'},
+ {value => '20130806-20130916', label => '2013-08-06 and 2013-09-16'},
+ {value => '20130625-20130805', label => '2013-06-25 and 2013-08-05'},
+ {value => '20130514-20130624', label => '2013-05-14 and 2013-06-24'},
+ {value => '20130402-20130513', label => '2013-04-02 and 2013-05-13'},
+ {value => '20130219-20130401', label => '2013-02-19 and 2013-04-01'},
+ {value => '20130108-20130218', label => '2013-01-08 and 2013-02-18'},
+ {value => '20121120-20130107', label => '2012-11-20 and 2013-01-07'},
+ {value => '20121009-20121119', label => '2012-10-09 and 2012-11-19'},
+ {value => '20120828-20121008', label => '2012-08-28 and 2012-10-08'},
+ {value => '20120717-20120827', label => '2012-07-17 and 2012-08-27'},
+ {value => '20120605-20120716', label => '2012-06-05 and 2012-07-16'},
+ {value => '20120424-20120604', label => '2012-04-24 and 2012-06-04'},
+ {value => '20120313-20120423', label => '2012-03-13 and 2012-04-23'},
+ {value => '20120131-20120312', label => '2012-01-31 and 2012-03-12'},
+ {value => '20111220-20120130', label => '2011-12-20 and 2012-01-30'},
+ {value => '20111108-20111219', label => '2011-11-08 and 2011-12-19'},
+ {value => '20110927-20111107', label => '2011-09-27 and 2011-11-07'},
+ {value => '20110816-20110926', label => '2011-08-16 and 2011-09-26'},
+ {value => '*', label => 'Anytime'}
];
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;
- }
+ 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;
- }
- }
+ # 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+)/);
+ }
}
- @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 =
- sort { $a->sortkey <=> $b->sortkey }
- 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;
+ elsif (scalar keys %{$flag_type->exclusions}) {
+ my $exclusions = $flag_type->exclusions;
+ foreach my $key (keys %$exclusions) {
+ push @exclusion_ids, ($exclusions->{$key} =~ /^(\d+)/);
+ }
}
-
- # 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;
- }
+ else {
+ $has_all = 1;
+ last;
}
-
- # 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,
- desc => $field->description,
- id => $field->id,
- };
- }
+ }
+
+ 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;
+ }
+ }
}
- foreach my $rh (@flags_json) {
- my @fields = uniq @{$rh->{fields}};
- $rh->{fields} = \@fields;
+ @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
+ = sort { $a->sortkey <=> $b->sortkey }
+ 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;
}
- # remove products which aren't linked with status fields
+ # product
+ push @products_json,
+ {name => $product->name, id => $product->id, fields => \@field_ids,};
+ # add fields to flags
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;
+ 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, desc => $field->description, 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;
+ }
+ }
- #
- # run report
- #
+ #
+ # run report
+ #
- if ($input->{q} && !$input->{edit}) {
- my $q = _parse_query($input->{q});
+ if ($input->{q} && !$input->{edit}) {
+ my $q = _parse_query($input->{q});
- my @where;
- my @params;
- my $query = "
+ 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\n";
- if ($q->{start_date}) {
- $query .= "INNER JOIN bugs_activity a ON a.bug_id = b.bug_id\n";
- }
+ if ($q->{start_date}) {
+ $query .= "INNER JOIN bugs_activity a ON a.bug_id = b.bug_id\n";
+ }
- $query .= "WHERE ";
+ $query .= "WHERE ";
- if ($q->{start_date}) {
- push @where, "(a.fieldid = ?)";
- push @params, $q->{field_id};
+ if ($q->{start_date}) {
+ push @where, "(a.fieldid = ?)";
+ push @params, $q->{field_id};
- push @where, "(CONVERT_TZ(a.bug_when, 'UTC', 'America/Los_Angeles') >= ?)";
- push @params, $q->{start_date} . ' 00:00:00';
- push @where, "(CONVERT_TZ(a.bug_when, 'UTC', 'America/Los_Angeles') <= ?)";
- push @params, $q->{end_date} . ' 23:59:59';
+ push @where, "(CONVERT_TZ(a.bug_when, 'UTC', 'America/Los_Angeles') >= ?)";
+ push @params, $q->{start_date} . ' 00:00:00';
+ push @where, "(CONVERT_TZ(a.bug_when, 'UTC', 'America/Los_Angeles') <= ?)";
+ push @params, $q->{end_date} . ' 23:59:59';
- push @where, "(a.added LIKE ?)";
- push @params, '%' . $q->{flag_name} . $q->{flag_status} . '%';
- }
+ 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;
+ 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};
+ push @where, "(f.status = ?)";
+ push @params, $q->{flag_status};
- if ($q->{product_id}) {
- push @where, "(b.product_id = ?)";
- push @params, $q->{product_id};
- }
+ 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 .= "
+ if (scalar @{$q->{fields}}) {
+ my @fields;
+ foreach my $field (@{$q->{fields}}) {
+ my $field_sql = "(";
+ if ($field->{type} == FIELD_TYPE_EXTENSION) {
+ $field_sql .= "
COALESCE(
(SELECT tracking_flags_bugs.value
FROM tracking_flags_bugs
LEFT JOIN tracking_flags
ON tracking_flags.id = tracking_flags_bugs.tracking_flag_id
WHERE tracking_flags_bugs.bug_id = b.bug_id
- AND tracking_flags.name = " . $dbh->quote($field->{name}) . ")
+ AND tracking_flags.name = "
+ . $dbh->quote($field->{name}) . ")
, '') ";
- }
- 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);
-
- my $bugs = $dbh->selectcol_arrayref($query, undef, @params);
- push @$bugs, 0 unless @$bugs;
-
- my $urlbase = Bugzilla->localconfig->{urlbase};
- my $cgi = Bugzilla->cgi;
- print $cgi->redirect(
- -url => "${urlbase}buglist.cgi?bug_id=" . join(',', @$bugs)
- );
- exit;
+ 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) . ')';
}
- #
- # set template vars
- #
-
- my $json = JSON->new()->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} = DATE_RANGES;
- $vars->{default_query} = $input->{q};
- $vars->{is_custom} = $input->{is_custom};
- foreach my $field (qw(product flags range)) {
- $vars->{$field} = $input->{$field};
- }
+ $query .= join("\nAND ", @where);
+
+ my $bugs = $dbh->selectcol_arrayref($query, undef, @params);
+ push @$bugs, 0 unless @$bugs;
+
+ my $urlbase = Bugzilla->localconfig->{urlbase};
+ my $cgi = Bugzilla->cgi;
+ print $cgi->redirect(
+ -url => "${urlbase}buglist.cgi?bug_id=" . join(',', @$bugs));
+ exit;
+ }
+
+ #
+ # set template vars
+ #
+
+ my $json = JSON->new()->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} = DATE_RANGES;
+ $vars->{default_query} = $input->{q};
+ $vars->{is_custom} = $input->{is_custom};
+ 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";
- validate_date($query->{start_date})
- || ThrowUserError('illegal_date', { date => $query->{start_date},
- format => 'YYYY-MM-DD' });
- validate_date($query->{end_date})
- || ThrowUserError('illegal_date', { date => $query->{end_date},
- format => 'YYYY-MM-DD' });
- }
-
- # 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;
+ 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";
+ validate_date($query->{start_date})
+ || ThrowUserError('illegal_date',
+ {date => $query->{start_date}, format => 'YYYY-MM-DD'});
+ validate_date($query->{end_date})
+ || ThrowUserError('illegal_date',
+ {date => $query->{end_date}, format => 'YYYY-MM-DD'});
+ }
+
+ # 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
index 55eeb17eb..0ccbbee6e 100644
--- a/extensions/BMO/lib/Reports/Triage.pm
+++ b/extensions/BMO/lib/Reports/Triage.pm
@@ -25,261 +25,279 @@ use List::MoreUtils qw(any);
# set an upper limit on the *unfiltered* number of bugs to process
use constant MAX_NUMBER_BUGS => 4000;
-use constant DEFAULT_OWNER_PRODUCTS => (
- 'Core',
- 'Firefox',
- 'Firefox for Android',
- 'Firefox for iOS',
- 'Toolkit',
-);
+use constant DEFAULT_OWNER_PRODUCTS =>
+ ('Core', 'Firefox', 'Firefox for Android', 'Firefox for iOS', 'Toolkit',);
sub unconfirmed {
- 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;
- }
- }
+ my ($vars, $filter) = @_;
+ my $dbh = Bugzilla->dbh;
+ my $input = Bugzilla->input_params;
+ my $user = Bugzilla->user;
- # determine which comment filters to run
+ if ( exists $input->{'action'}
+ && $input->{'action'} eq 'run'
+ && $input->{'product'})
+ {
- my $filter_commenter = $input->{'filter_commenter'};
- my $filter_commenter_on = $input->{'commenter'};
- my $filter_last = $input->{'filter_last'};
- my $filter_last_period = $input->{'last'};
+ # load product and components from input
- if (!$filter_commenter || $filter_last) {
- $filter_commenter = '1';
- $filter_commenter_on = 'reporter';
- }
+ my $product
+ = Bugzilla::Product->new({name => $input->{'product'}})
+ || ThrowUserError('invalid_object',
+ {object => 'Product', value => $input->{'product'}});
- 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 @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;
+ }
+ }
- 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;
- }
- }
+ # 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;
+ }
- # form sql queries
+ 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 = "
+ 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 .= "
+ if (@component_ids) {
+ $bugs_sql .= " AND component_id IN (" . join(',', @component_ids) . ")";
+ }
+ $bugs_sql .= "
ORDER BY creation_ts
";
- my $comment_count_sql = "
+ my $comment_count_sql = "
SELECT COUNT(*)
FROM longdescs
WHERE bug_id = ?
";
- my $comment_sql = "
+ 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 .= "
+ if (!Bugzilla->user->is_insider) {
+ $comment_sql .= " AND isprivate = 0 ";
+ }
+ $comment_sql .= "
ORDER BY bug_when DESC
LIMIT 1
";
- my $attach_sql = "
+ my $attach_sql = "
SELECT description, isprivate
FROM attachments
WHERE attach_id = ?
";
- # work on an initial list of bugs
+ # work on an initial list of bugs
- my $list = $dbh->selectall_arrayref($bugs_sql, undef, $product->id);
- my @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
+ # 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');
- }
+ 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;
- }
+ foreach my $entry (@$list) {
+ my ($bug_id, $summary, $reporter_id, $creation_ts) = @$entry;
- @bugs = sort { $b->{comment_ts} cmp $a->{comment_ts} } @bugs;
+ next unless $user->can_see_bug($bug_id);
- $vars->{bugs} = \@bugs;
- } else {
- $input->{action} = '';
- }
+ # get last comment information
- if (!$input->{filter_commenter} && !$input->{filter_last}) {
- $input->{filter_commenter} = 1;
- }
+ 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;
- $vars->{'input'} = $input;
-}
+ # apply selected filters
-sub owners {
- my ($vars, $filter) = @_;
- my $dbh = Bugzilla->dbh;
- my $input = Bugzilla->input_params;
- my $user = Bugzilla->user;
+ if ($filter_commenter) {
+ next if $comment_count <= 1;
- Bugzilla::User::match_field({ 'owner' => {'type' => 'multi'} });
+ if ($filter_commenter_on eq 'reporter') {
+ next if $commenter_id != $reporter_id;
- my @products;
- if (!$input->{product} && $input->{owner}) {
- @products = @{ $user->get_selectable_products };
- }
- else {
- my @product_names = $input->{product} ? ($input->{product}) : DEFAULT_OWNER_PRODUCTS;
- foreach my $name (@product_names) {
- push(@products, Bugzilla::Product->check({ name => $name }));
}
- }
+ 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');
- my @component_ids;
- if (@products == 1 && $input->{'component'}) {
- my $ra_components = ref($input->{'component'})
- ? $input->{'component'}
- : [ $input->{'component'} ];
- foreach my $component_name (@$ra_components) {
- my $component = Bugzilla::Component->check({ name => $component_name, product => $products[0] });
- push @component_ids, $component->id;
}
+ 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;
}
- my @owner_names = split(/[,;]+/, $input->{owner}) if $input->{owner};
- my @owner_ids;
- foreach my $name (@owner_names) {
- $name = trim($name);
- next unless $name;
- push(@owner_ids, login_to_id($name, THROW_ERROR));
- }
+ @bugs = sort { $b->{comment_ts} cmp $a->{comment_ts} } @bugs;
- my $sql = "SELECT products.name, components.name, components.id, components.triage_owner_id
- FROM components JOIN products ON components.product_id = products.id
- WHERE products.id IN (" . join(',', map { $_->id } @products) . ")";
- if (@component_ids) {
- $sql .= " AND components.id IN (" . join(',', @component_ids) . ")";
- }
- if (@owner_ids) {
- $sql .= " AND components.triage_owner_id IN (" . join(',', @owner_ids) . ")";
- }
- $sql .= " ORDER BY products.name, components.name";
+ $vars->{bugs} = \@bugs;
+ }
+ else {
+ $input->{action} = '';
+ }
- my $rows = $dbh->selectall_arrayref($sql);
+ if (!$input->{filter_commenter} && !$input->{filter_last}) {
+ $input->{filter_commenter} = 1;
+ }
- my $bug_count_sth = $dbh->prepare("
+ $vars->{'input'} = $input;
+}
+
+sub owners {
+ my ($vars, $filter) = @_;
+ my $dbh = Bugzilla->dbh;
+ my $input = Bugzilla->input_params;
+ my $user = Bugzilla->user;
+
+ Bugzilla::User::match_field({'owner' => {'type' => 'multi'}});
+
+ my @products;
+ if (!$input->{product} && $input->{owner}) {
+ @products = @{$user->get_selectable_products};
+ }
+ else {
+ my @product_names
+ = $input->{product} ? ($input->{product}) : DEFAULT_OWNER_PRODUCTS;
+ foreach my $name (@product_names) {
+ push(@products, Bugzilla::Product->check({name => $name}));
+ }
+ }
+
+ my @component_ids;
+ if (@products == 1 && $input->{'component'}) {
+ my $ra_components
+ = ref($input->{'component'})
+ ? $input->{'component'}
+ : [$input->{'component'}];
+ foreach my $component_name (@$ra_components) {
+ my $component = Bugzilla::Component->check(
+ {name => $component_name, product => $products[0]});
+ push @component_ids, $component->id;
+ }
+ }
+
+ my @owner_names = split(/[,;]+/, $input->{owner}) if $input->{owner};
+ my @owner_ids;
+ foreach my $name (@owner_names) {
+ $name = trim($name);
+ next unless $name;
+ push(@owner_ids, login_to_id($name, THROW_ERROR));
+ }
+
+ my $sql
+ = "SELECT products.name, components.name, components.id, components.triage_owner_id
+ FROM components JOIN products ON components.product_id = products.id
+ WHERE products.id IN ("
+ . join(',', map { $_->id } @products) . ")";
+ if (@component_ids) {
+ $sql .= " AND components.id IN (" . join(',', @component_ids) . ")";
+ }
+ if (@owner_ids) {
+ $sql .= " AND components.triage_owner_id IN (" . join(',', @owner_ids) . ")";
+ }
+ $sql .= " ORDER BY products.name, components.name";
+
+ my $rows = $dbh->selectall_arrayref($sql);
+
+ my $bug_count_sth = $dbh->prepare("
SELECT COUNT(bugs.bug_id)
FROM bugs INNER JOIN components AS map_component ON bugs.component_id = map_component.id
INNER JOIN bug_status AS map_bug_status ON bugs.bug_status = map_bug_status.value
@@ -296,55 +314,57 @@ sub owners {
WHERE bugs_1.bug_id = bugs.bug_id AND CONCAT(flagtypes_1.name, flags_1.status) = 'needinfo?')))
AND bugs.component_id = ?");
- my @results;
- foreach my $row (@$rows) {
- my ($product_name, $component_name, $component_id, $triage_owner_id) = @$row;
- my $triage_owner = $triage_owner_id
- ? Bugzilla::User->new({ id => $triage_owner_id, cache => 1 })
- : "";
- my $data = {
- product => $product_name,
- component => $component_name,
- owner => $triage_owner,
- };
- $data->{buglist_url} = 'priority=--&resolution=---&f1=creation_ts&o1=greaterthaneq&v1=2016-06-01'.
- '&f2=flagtypes.name&o2=notequals&v2=needinfo%3F';
- if ($triage_owner) {
- $data->{buglist_url} .= '&f3=triage_owner&o3=equals&v3=' . url_quote($triage_owner->login);
- }
- $bug_count_sth->execute($component_id);
- ($data->{bug_count}) = $bug_count_sth->fetchrow_array();
- push @results, $data;
+ my @results;
+ foreach my $row (@$rows) {
+ my ($product_name, $component_name, $component_id, $triage_owner_id) = @$row;
+ my $triage_owner
+ = $triage_owner_id
+ ? Bugzilla::User->new({id => $triage_owner_id, cache => 1})
+ : "";
+ my $data = {
+ product => $product_name,
+ component => $component_name,
+ owner => $triage_owner,
+ };
+ $data->{buglist_url}
+ = 'priority=--&resolution=---&f1=creation_ts&o1=greaterthaneq&v1=2016-06-01'
+ . '&f2=flagtypes.name&o2=notequals&v2=needinfo%3F';
+ if ($triage_owner) {
+ $data->{buglist_url}
+ .= '&f3=triage_owner&o3=equals&v3=' . url_quote($triage_owner->login);
}
- $vars->{results} = \@results;
-
- my $json_data = { products => [] };
- foreach my $product (@{ $user->get_selectable_products }) {
- my $prod_data = {
- name => $product->name,
- components => [],
- };
- foreach my $component (@{ $product->components }) {
- my $selected = 0;
- if ($input->{product}
- && $input->{product} eq $product->name
- && $input->{component})
- {
- $selected = 1 if (ref $input->{component} && any { $_ eq $component->name } @{ $input->{component} });
- $selected = 1 if (!ref $input->{componet} && $input->{component} eq $component->name);
- }
- my $comp_data = {
- name => $component->name,
- selected => $selected
- };
- push(@{ $prod_data->{components} }, $comp_data);
- }
- push(@{ $json_data->{products} }, $prod_data);
+ $bug_count_sth->execute($component_id);
+ ($data->{bug_count}) = $bug_count_sth->fetchrow_array();
+ push @results, $data;
+ }
+ $vars->{results} = \@results;
+
+ my $json_data = {products => []};
+ foreach my $product (@{$user->get_selectable_products}) {
+ my $prod_data = {name => $product->name, components => [],};
+ foreach my $component (@{$product->components}) {
+ my $selected = 0;
+ if ( $input->{product}
+ && $input->{product} eq $product->name
+ && $input->{component})
+ {
+ $selected = 1
+ if (
+ ref $input->{component} && any { $_ eq $component->name }
+ @{$input->{component}}
+ );
+ $selected = 1
+ if (!ref $input->{componet} && $input->{component} eq $component->name);
+ }
+ my $comp_data = {name => $component->name, selected => $selected};
+ push(@{$prod_data->{components}}, $comp_data);
}
+ push(@{$json_data->{products}}, $prod_data);
+ }
- $vars->{product} = $input->{product};
- $vars->{owner} = $input->{owner};
- $vars->{json_data} = encode_json($json_data);
+ $vars->{product} = $input->{product};
+ $vars->{owner} = $input->{owner};
+ $vars->{json_data} = encode_json($json_data);
}
1;
diff --git a/extensions/BMO/lib/Reports/UserActivity.pm b/extensions/BMO/lib/Reports/UserActivity.pm
index 8dfe0c5cd..3be6f74c9 100644
--- a/extensions/BMO/lib/Reports/UserActivity.pm
+++ b/extensions/BMO/lib/Reports/UserActivity.pm
@@ -18,104 +18,104 @@ 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('-');
+ 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');
}
- 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'} });
+ Bugzilla::User::match_field({'who' => {'type' => 'multi'}});
- my $from_dt = string_to_datetime($from);
- $from = $from_dt->ymd();
+ my $from_dt = string_to_datetime($from);
+ $from = $from_dt->ymd();
- my $to_dt = string_to_datetime($to);
- $to = $to_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
+ 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;
+ $activity_where = "AND COALESCE(attachments.isprivate, 0) = 0";
+ $attachments_where = $activity_where;
- $tags_activity_joins = 'LEFT JOIN longdescs
+ $tags_activity_joins = 'LEFT JOIN longdescs
ON longdescs_tags_activity.comment_id = longdescs.comment_id';
- $tags_activity_where = 'AND COALESCE(longdescs.isprivate, 0) = 0';
- }
+ $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;
- }
+ 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);
- }
+ $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 $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 $comment_filter = '';
+ if (!Bugzilla->user->is_insider) {
+ $comment_filter = 'AND longdescs.isprivate = 0';
+ }
- my $query = "
+ 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,
+ "
+ . $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,
@@ -138,8 +138,10 @@ sub report {
'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,
+ "
+ . $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,
@@ -160,7 +162,8 @@ sub report {
'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,
+ "
+ . $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,
@@ -199,7 +202,9 @@ sub report {
'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,
+ "
+ . $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,
@@ -215,119 +220,118 @@ sub report {
ORDER BY $order ";
- my $list = $dbh->selectall_arrayref($query, undef, @params);
+ 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;
+ 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;
}
- 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);
- }
+ # 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;
- if ($operation->{'who'}) {
- $operation->{'changes'} = $changes;
- push (@operations, $operation);
+ $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);
}
- $vars->{'incomplete_data'} = $incomplete_data;
- $vars->{'operations'} = \@operations;
+ push(@$changes, \%change);
+ }
+ }
- my @bug_ids = sort { $a <=> $b } keys %bug_ids;
- $vars->{'bug_ids'} = \@bug_ids;
+ if ($operation->{'who'}) {
+ $operation->{'changes'} = $changes;
+ push(@operations, $operation);
}
- $vars->{'action'} = $action;
- $vars->{'who'} = join(',', @who);
- $vars->{'who_count'} = scalar @who;
- $vars->{'from'} = $from;
- $vars->{'to'} = $to;
- $vars->{'group'} = $input->{'group'};
+ $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
index dc9c904f9..4d376aecb 100644
--- a/extensions/BMO/lib/Util.pm
+++ b/extensions/BMO/lib/Util.pm
@@ -19,74 +19,77 @@ use DateTime;
use base qw(Exporter);
our @EXPORT = qw( string_to_datetime
- time_to_datetime
- parse_date
- is_active_status_field );
+ 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);
+ 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');
+ 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;
+ 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));
}
- return str2time($str);
+ 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) = @_;
+ 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;
- }
+ 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;
+ return 0;
}
1;
diff --git a/extensions/BMO/lib/WebService.pm b/extensions/BMO/lib/WebService.pm
index 327c8563f..4c9187254 100644
--- a/extensions/BMO/lib/WebService.pm
+++ b/extensions/BMO/lib/WebService.pm
@@ -32,26 +32,26 @@ use Bugzilla::WebService::Util qw(validate);
use Bugzilla::Field;
use constant PUBLIC_METHODS => qw(
- getBugsConfirmer
- getBugsVerifier
+ getBugsConfirmer
+ getBugsVerifier
);
sub getBugsConfirmer {
- my ($self, $params) = validate(@_, 'names');
- my $dbh = Bugzilla->dbh;
+ my ($self, $params) = validate(@_, 'names');
+ my $dbh = Bugzilla->dbh;
- defined($params->{names})
- || ThrowCodeError('params_required',
- { function => 'BMO.getBugsConfirmer', params => ['names'] });
+ defined($params->{names})
+ || ThrowCodeError('params_required',
+ {function => 'BMO.getBugsConfirmer', params => ['names']});
- my @user_objects = map { Bugzilla::User->check($_) } @{ $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 }};
+ # start filtering to remove duplicate user ids
+ @user_objects = values %{{map { $_->id => $_ } @user_objects}};
- my $fieldid = get_field_id('bug_status');
+ my $fieldid = get_field_id('bug_status');
- my $query = "SELECT DISTINCT bugs_activity.bug_id
+ 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
@@ -62,31 +62,31 @@ sub getBugsConfirmer {
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;
- }
+ my %users;
+ foreach my $user (@user_objects) {
+ my $bugs = $dbh->selectcol_arrayref($query, undef, $fieldid, $user->id);
+ $users{$user->login} = $bugs;
+ }
- return \%users;
+ return \%users;
}
sub getBugsVerifier {
- my ($self, $params) = validate(@_, 'names');
- my $dbh = Bugzilla->dbh;
+ my ($self, $params) = validate(@_, 'names');
+ my $dbh = Bugzilla->dbh;
- defined($params->{names})
- || ThrowCodeError('params_required',
- { function => 'BMO.getBugsVerifier', params => ['names'] });
+ defined($params->{names})
+ || ThrowCodeError('params_required',
+ {function => 'BMO.getBugsVerifier', params => ['names']});
- my @user_objects = map { Bugzilla::User->check($_) } @{ $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 }};
+ # start filtering to remove duplicate user ids
+ @user_objects = values %{{map { $_->id => $_ } @user_objects}};
- my $fieldid = get_field_id('bug_status');
+ my $fieldid = get_field_id('bug_status');
- my $query = "SELECT DISTINCT bugs_activity.bug_id
+ 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
@@ -97,13 +97,13 @@ sub getBugsVerifier {
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;
- }
+ my %users;
+ foreach my $user (@user_objects) {
+ my $bugs = $dbh->selectcol_arrayref($query, undef, $fieldid, $user->id);
+ $users{$user->login} = $bugs;
+ }
- return \%users;
+ return \%users;
}
1;
diff --git a/extensions/BMO/t/bounty_attachment.t b/extensions/BMO/t/bounty_attachment.t
index 6e596eeba..61552c074 100644
--- a/extensions/BMO/t/bounty_attachment.t
+++ b/extensions/BMO/t/bounty_attachment.t
@@ -13,46 +13,69 @@ use Test::More;
use Bugzilla;
BEGIN { Bugzilla->extensions }
-my $class = 'Bugzilla::Extension::BMO';
+my $class = 'Bugzilla::Extension::BMO';
my $parse = $class->can('parse_bounty_attachment_description');
my $format = $class->can('format_bounty_attachment_description');
ok($parse, "got the function");
my $bughunter = $parse->('bughunter@hacker.org, , 2014-06-25, , ,false');
-is_deeply({ reporter_email => 'bughunter@hacker.org',
- amount_paid => '',
- reported_date => '2014-06-25',
- fixed_date => '',
- awarded_date => '',
- publish => 0,
- credit => []}, $bughunter);
-
-my $hfli = $parse->('hfli@fortinet.com, 1000, 2010-07-16, 2010-08-04, 2011-06-15, true, Fortiguard Labs');
-is_deeply({ reporter_email => 'hfli@fortinet.com',
- amount_paid => '1000',
- reported_date => '2010-07-16',
- fixed_date => '2010-08-04',
- awarded_date => '2011-06-15',
- publish => 1,
- credit => ['Fortiguard Labs']}, $hfli);
-
-is('batman@justiceleague.america,1000,2015-01-01,2015-02-02,2015-03-03,true,JLA,Wayne Industries,Test',
- $format->({ reporter_email => 'batman@justiceleague.america',
- amount_paid => 1000,
- reported_date => '2015-01-01',
- fixed_date => '2015-02-02',
- awarded_date => '2015-03-03',
- publish => 1,
- credit => ['JLA', 'Wayne Industries', 'Test'] }));
-
-my $dylan = $parse->('dylan@hardison.net,2,2014-09-23,2014-09-24,2014-09-25,true,Foo bar,Bork,');
-is_deeply({ reporter_email => 'dylan@hardison.net',
- amount_paid => 2,
- reported_date => '2014-09-23',
- fixed_date => '2014-09-24',
- awarded_date => '2014-09-25',
- publish => 1,
- credit => ['Foo bar', 'Bork']}, $dylan);
+is_deeply(
+ {
+ reporter_email => 'bughunter@hacker.org',
+ amount_paid => '',
+ reported_date => '2014-06-25',
+ fixed_date => '',
+ awarded_date => '',
+ publish => 0,
+ credit => []
+ },
+ $bughunter
+);
+
+my $hfli
+ = $parse->(
+ 'hfli@fortinet.com, 1000, 2010-07-16, 2010-08-04, 2011-06-15, true, Fortiguard Labs'
+ );
+is_deeply(
+ {
+ reporter_email => 'hfli@fortinet.com',
+ amount_paid => '1000',
+ reported_date => '2010-07-16',
+ fixed_date => '2010-08-04',
+ awarded_date => '2011-06-15',
+ publish => 1,
+ credit => ['Fortiguard Labs']
+ },
+ $hfli
+);
+
+is(
+ 'batman@justiceleague.america,1000,2015-01-01,2015-02-02,2015-03-03,true,JLA,Wayne Industries,Test',
+ $format->({
+ reporter_email => 'batman@justiceleague.america',
+ amount_paid => 1000,
+ reported_date => '2015-01-01',
+ fixed_date => '2015-02-02',
+ awarded_date => '2015-03-03',
+ publish => 1,
+ credit => ['JLA', 'Wayne Industries', 'Test']
+ })
+);
+
+my $dylan = $parse->(
+ 'dylan@hardison.net,2,2014-09-23,2014-09-24,2014-09-25,true,Foo bar,Bork,');
+is_deeply(
+ {
+ reporter_email => 'dylan@hardison.net',
+ amount_paid => 2,
+ reported_date => '2014-09-23',
+ fixed_date => '2014-09-24',
+ awarded_date => '2014-09-25',
+ publish => 1,
+ credit => ['Foo bar', 'Bork']
+ },
+ $dylan
+);
done_testing;