diff options
171 files changed, 5847 insertions, 1084 deletions
diff --git a/.bzrignore b/.bzrignore index 7ab83e7ad..e009f01c8 100644 --- a/.bzrignore +++ b/.bzrignore @@ -6,7 +6,6 @@ /docs/en/txt /docs/en/html /docs/en/pdf -/skins/custom /graphs /data /localconfig @@ -23,3 +23,18 @@ </IfModule> </IfModule> </IfModule> + +Redirect permanent /queryhelp.cgi https://bugzilla.mozilla.org/query.cgi?format=advanced&help=1 +Redirect permanent /bug_status.html https://bugzilla.mozilla.org/page.cgi?id=fields.html +Redirect permanent /bugwritinghelp.html https://bugzilla.mozilla.org/page.cgi?id=bug-writing.html +Redirect permanent /etiquette.html https://bugzilla.mozilla.org/page.cgi?id=etiquette.html +Redirect permanent /duplicates.html https://bugzilla.mozilla.org/duplicates.cgi + +RewriteEngine On +RewriteRule ^form[\.:](itrequest|brownbag|mozlist|mktgevent|poweredby|presentation|swag|trademark)$ enter_bug.cgi?product=mozilla.org&format=$1 +RewriteRule ^form[\.:]legal$ enter_bug.cgi?product=Legal&format=legal +RewriteRule ^form[\.:]mozpr$ enter_bug.cgi?product=Mozilla+PR&format=mozpr +RewriteRule ^form[\.:]reps[\.:]mentorship$ enter_bug.cgi?product=Mozilla+Reps&format=mozreps +RewriteRule ^form[\.:]reps[\.:]budget$ enter_bug.cgi?product=Mozilla+Reps&format=remo-budget +RewriteRule ^form[\.:]reps[\.:]swag$ enter_bug.cgi?product=Mozilla+Reps&format=remo-swag +RewriteRule ^form[\.:]reps[\.:]payment$ page.cgi?id=remo-form-payment.html diff --git a/Bugzilla/Bug.pm b/Bugzilla/Bug.pm index 175bcd050..26d2a89f3 100644 --- a/Bugzilla/Bug.pm +++ b/Bugzilla/Bug.pm @@ -1628,6 +1628,14 @@ sub _check_groups { : $params->{product}; my %add_groups; + # BMO: Allow extension to add groups before the + # real checks are done. + Bugzilla::Hook::process('bug_check_groups', { + product => $product, + group_names => $group_names, + add_groups => \%add_groups + }); + # In email or WebServices, when the "groups" item actually # isn't specified, then just add the default groups. if (!defined $group_names) { @@ -1646,7 +1654,12 @@ sub _check_groups { foreach my $name (@$group_names) { my $group = Bugzilla::Group->check_no_disclose({ %args, name => $name }); - if (!$product->group_is_settable($group)) { + # BMO: Do not check group_is_settable if the group is + # already added, such as from the extension hook. group_is_settable + # will reject any group the user is not currently in. + if (!$add_groups{$group->id} + && !$product->group_is_settable($group)) + { ThrowUserError('group_restriction_not_allowed', { %args, name => $name }); } $add_groups{$group->id} = $group; @@ -1655,7 +1668,7 @@ sub _check_groups { # Now enforce mandatory groups. $add_groups{$_->id} = $_ foreach @{ $product->groups_mandatory }; - + my @add_groups = values %add_groups; return \@add_groups; } @@ -3244,15 +3257,37 @@ sub depends_on_obj { return $self->{depends_on_obj}; } +sub duplicates { + my $self = shift; + return $self->{duplicates} if exists $self->{duplicates}; + return [] if $self->{error}; + $self->{duplicates} = Bugzilla::Bug->new_from_list($self->duplicate_ids); + return $self->{duplicates}; +} + +sub duplicate_ids { + my $self = shift; + return $self->{duplicate_ids} if exists $self->{duplicate_ids}; + return [] if $self->{error}; + + my $dbh = Bugzilla->dbh; + $self->{duplicate_ids} = + $dbh->selectcol_arrayref('SELECT dupe FROM duplicates WHERE dupe_of = ?', + undef, $self->id); + return $self->{duplicate_ids}; +} + sub flag_types { - my ($self) = @_; + my ($self, $params) = @_; + $params ||= {}; return $self->{'flag_types'} if exists $self->{'flag_types'}; return [] if $self->{'error'}; my $vars = { target_type => 'bug', product_id => $self->{product_id}, component_id => $self->{component_id}, - bug_id => $self->bug_id }; + bug_id => $self->bug_id, + %$params }; $self->{'flag_types'} = Bugzilla::Flag->_flag_types($vars); return $self->{'flag_types'}; diff --git a/Bugzilla/BugMail.pm b/Bugzilla/BugMail.pm index 55eeeab25..c637c3a66 100644 --- a/Bugzilla/BugMail.pm +++ b/Bugzilla/BugMail.pm @@ -267,7 +267,12 @@ sub Send { } # Make sure the user isn't in the nomail list, and the dep check passed. - if ($user->email_enabled && $dep_ok) { + # Upstreaming: when we port to 4.2, check the login names of the + # user objects in the bugmail_recipients hook instead. + if ($user->email_enabled && $dep_ok && + ($user->login !~ /bugs$/) && + ($user->login !~ /\.tld$/)) + { # OK, OK, if we must. Email the user. $sent_mail = sendMail( { to => $user, diff --git a/Bugzilla/Component.pm b/Bugzilla/Component.pm index dc3cc1b9e..ad5166a0f 100644 --- a/Bugzilla/Component.pm +++ b/Bugzilla/Component.pm @@ -371,11 +371,13 @@ sub default_qa_contact { } sub flag_types { - my $self = shift; + my ($self, $params) = @_; + $params ||= {}; if (!defined $self->{'flag_types'}) { my $flagtypes = Bugzilla::FlagType::match({ product_id => $self->product_id, - component_id => $self->id }); + component_id => $self->id, + %$params }); $self->{'flag_types'} = {}; $self->{'flag_types'}->{'bug'} = diff --git a/Bugzilla/Config/Advanced.pm b/Bugzilla/Config/Advanced.pm index faab6bbbd..f5653ee86 100644 --- a/Bugzilla/Config/Advanced.pm +++ b/Bugzilla/Config/Advanced.pm @@ -62,6 +62,12 @@ use constant get_param_list => ( default => 'off', checker => \&check_multi }, + + { + name => 'disable_bug_updates', + type => 'b', + default => 0 + }, ); 1; diff --git a/Bugzilla/Constants.pm b/Bugzilla/Constants.pm index 5c9fecc57..62836d8cc 100644 --- a/Bugzilla/Constants.pm +++ b/Bugzilla/Constants.pm @@ -255,7 +255,8 @@ use constant AUTH_NO_SUCH_USER => 5; use constant AUTH_LOCKOUT => 6; # The minimum length a password must have. -use constant USER_PASSWORD_MIN_LENGTH => 6; +# BMO uses 8 characters. +use constant USER_PASSWORD_MIN_LENGTH => 8; use constant LOGIN_OPTIONAL => 0; use constant LOGIN_NORMAL => 1; @@ -424,8 +425,8 @@ use constant MAX_LOGIN_ATTEMPTS => 5; use constant LOGIN_LOCKOUT_INTERVAL => 30; # The maximum number of seconds the Strict-Transport-Security header -# will remain valid. Default is one week. -use constant MAX_STS_AGE => 604800; +# will remain valid. BMO uses one month. +use constant MAX_STS_AGE => 2629744; # Protocols which are considered as safe. use constant SAFE_PROTOCOLS => ('afs', 'cid', 'ftp', 'gopher', 'http', 'https', @@ -438,15 +439,16 @@ use constant LEGAL_CONTENT_TYPES => ('application', 'audio', 'image', 'message', use constant contenttypes => { - "html"=> "text/html" , - "rdf" => "application/rdf+xml" , - "atom"=> "application/atom+xml" , - "xml" => "application/xml" , - "js" => "application/x-javascript" , - "json"=> "application/json" , - "csv" => "text/csv" , - "png" => "image/png" , - "ics" => "text/calendar" , + "html" => "text/html" , + "rdf" => "application/rdf+xml" , + "atom" => "application/atom+xml" , + "xml" => "application/xml" , + "dtd" => "application/xml-dtd" , + "js" => "application/x-javascript" , + "json" => "application/json" , + "csv" => "text/csv" , + "png" => "image/png" , + "ics" => "text/calendar" , }; # Usage modes. Default USAGE_MODE_BROWSER. Use with Bugzilla->usage_mode. diff --git a/Bugzilla/Error.pm b/Bugzilla/Error.pm index 395cc0dc9..17a7a948a 100644 --- a/Bugzilla/Error.pm +++ b/Bugzilla/Error.pm @@ -26,7 +26,7 @@ package Bugzilla::Error; use strict; use base qw(Exporter); -@Bugzilla::Error::EXPORT = qw(ThrowCodeError ThrowTemplateError ThrowUserError); +@Bugzilla::Error::EXPORT = qw(ThrowCodeError ThrowTemplateError ThrowUserError ThrowErrorPage); use Bugzilla::Constants; use Bugzilla::WebService::Constants; @@ -212,6 +212,44 @@ END exit; } +sub ThrowErrorPage { + # BMO customisation for bug 659231 + my ($template_name, $message) = @_; + + my $dbh = Bugzilla->dbh; + $dbh->bz_rollback_transaction() if $dbh->bz_in_transaction(); + + if (Bugzilla->error_mode == ERROR_MODE_DIE) { + die("error: $message"); + } + + if (Bugzilla->error_mode == ERROR_MODE_DIE_SOAP_FAULT + || Bugzilla->error_mode == ERROR_MODE_JSON_RPC) + { + my $code = ERROR_UNKNOWN_TRANSIENT; + if (Bugzilla->error_mode == ERROR_MODE_DIE_SOAP_FAULT) { + die SOAP::Fault->faultcode($code)->faultstring($message); + } else { + my $server = Bugzilla->_json_server; + $server->raise_error(code => 100000 + $code, + message => $message, + id => $server->{_bz_request_id}, + version => $server->version); + die if _in_eval(); + $server->response($server->error_response_header); + } + } else { + my $cgi = Bugzilla->cgi; + my $template = Bugzilla->template; + my $vars = {}; + $vars->{message} = $message; + print $cgi->header(); + $template->process($template_name, $vars) + || ThrowTemplateError($template->error()); + exit; + } +} + 1; __END__ diff --git a/Bugzilla/Field.pm b/Bugzilla/Field.pm index 219172094..e47e92231 100644 --- a/Bugzilla/Field.pm +++ b/Bugzilla/Field.pm @@ -78,6 +78,8 @@ use Bugzilla::Constants; use Bugzilla::Error; use Bugzilla::Util; use List::MoreUtils qw(any); +use Bugzilla::Config qw(SetParam write_params); +use Bugzilla::Hook; use Scalar::Util qw(blessed); @@ -916,53 +918,64 @@ sub remove_from_db { ThrowUserError('customfield_not_obsolete', {'name' => $self->name }); } - $dbh->bz_start_transaction(); + # BMO: disable bug updates during field creation + # using an eval as try/finally + eval { + SetParam('disable_bug_updates', 1); + write_params(); - # Check to see if bug activity table has records (should be fast with index) - my $has_activity = $dbh->selectrow_array("SELECT COUNT(*) FROM bugs_activity - WHERE fieldid = ?", undef, $self->id); - if ($has_activity) { - ThrowUserError('customfield_has_activity', {'name' => $name }); - } + $dbh->bz_start_transaction(); + + # Check to see if bug activity table has records (should be fast with index) + my $has_activity = $dbh->selectrow_array("SELECT COUNT(*) FROM bugs_activity + WHERE fieldid = ?", undef, $self->id); + if ($has_activity) { + ThrowUserError('customfield_has_activity', {'name' => $name }); + } - # Check to see if bugs table has records (slow) - my $bugs_query = ""; + # Check to see if bugs table has records (slow) + my $bugs_query = ""; - if ($self->type == FIELD_TYPE_MULTI_SELECT) { - $bugs_query = "SELECT COUNT(*) FROM bug_$name"; - } - else { - $bugs_query = "SELECT COUNT(*) FROM bugs WHERE $name IS NOT NULL"; - if ($self->type != FIELD_TYPE_BUG_ID && $self->type != FIELD_TYPE_DATETIME) { - $bugs_query .= " AND $name != ''"; + if ($self->type == FIELD_TYPE_MULTI_SELECT) { + $bugs_query = "SELECT COUNT(*) FROM bug_$name"; } - # Ignore the default single select value - if ($self->type == FIELD_TYPE_SINGLE_SELECT) { - $bugs_query .= " AND $name != '---'"; + else { + $bugs_query = "SELECT COUNT(*) FROM bugs WHERE $name IS NOT NULL"; + if ($self->type != FIELD_TYPE_BUG_ID && $self->type != FIELD_TYPE_DATETIME) { + $bugs_query .= " AND $name != ''"; + } + # Ignore the default single select value + if ($self->type == FIELD_TYPE_SINGLE_SELECT) { + $bugs_query .= " AND $name != '---'"; + } } - } - my $has_bugs = $dbh->selectrow_array($bugs_query); - if ($has_bugs) { - ThrowUserError('customfield_has_contents', {'name' => $name }); - } + my $has_bugs = $dbh->selectrow_array($bugs_query); + if ($has_bugs) { + ThrowUserError('customfield_has_contents', {'name' => $name }); + } - # Once we reach here, we should be OK to delete. - $dbh->do('DELETE FROM fielddefs WHERE id = ?', undef, $self->id); + # Once we reach here, we should be OK to delete. + $dbh->do('DELETE FROM fielddefs WHERE id = ?', undef, $self->id); - my $type = $self->type; + my $type = $self->type; - # the values for multi-select are stored in a seperate table - if ($type != FIELD_TYPE_MULTI_SELECT) { - $dbh->bz_drop_column('bugs', $name); - } + # the values for multi-select are stored in a seperate table + if ($type != FIELD_TYPE_MULTI_SELECT) { + $dbh->bz_drop_column('bugs', $name); + } - if ($self->is_select) { - # Delete the table that holds the legal values for this field. - $dbh->bz_drop_field_tables($self); - } + if ($self->is_select) { + # Delete the table that holds the legal values for this field. + $dbh->bz_drop_field_tables($self); + } - $dbh->bz_commit_transaction() + $dbh->bz_commit_transaction(); + }; + my $error = "$@"; + SetParam('disable_bug_updates', 0); + write_params(); + die $error if $error; } =pod @@ -1014,36 +1027,72 @@ sub create { # the parameter isn't sent to create(). $params->{sortkey} = undef if !exists $params->{sortkey}; $params->{type} ||= 0; - - $dbh->bz_start_transaction(); - $class->check_required_create_fields(@_); - my $field_values = $class->run_create_validators($params); - my $visibility_values = delete $field_values->{visibility_values}; - my $field = $class->insert_create_data($field_values); - - $field->set_visibility_values($visibility_values); - $field->_update_visibility_values(); - - $dbh->bz_commit_transaction(); - if ($field->custom) { - my $name = $field->name; - my $type = $field->type; - if (SQL_DEFINITIONS->{$type}) { - # Create the database column that stores the data for this field. - $dbh->bz_add_column('bugs', $name, SQL_DEFINITIONS->{$type}); + # BMO: disable bug updates during field creation + # using an eval as try/finally + my $field; + eval { + if ($params->{'custom'}) { + SetParam('disable_bug_updates', 1); + write_params(); } - if ($field->is_select) { - # Create the table that holds the legal values for this field. - $dbh->bz_add_field_tables($field); + # Purpose: if the field is active in the fields list before all of the + # data structures are created, anything accessing Bug.pm will crash. So + # stash a copy of the intended obsolete value for later and force it + # to be obsolete on initial creation. + # Upstreaming: https://bugzilla.mozilla.org/show_bug.cgi?id=531243 + my $original_obsolete; + if ($params->{'custom'}) { + $original_obsolete = $params->{'obsolete'}; + $params->{'obsolete'} = 1; } - if ($type == FIELD_TYPE_SINGLE_SELECT) { - # Insert a default value of "---" into the legal values table. - $dbh->do("INSERT INTO $name (value) VALUES ('---')"); + $dbh->bz_start_transaction(); + $class->check_required_create_fields(@_); + my $field_values = $class->run_create_validators($params); + my $visibility_values = delete $field_values->{visibility_values}; + my $field = $class->insert_create_data($field_values); + + $field->set_visibility_values($visibility_values); + $field->_update_visibility_values(); + + $dbh->bz_commit_transaction(); + + if ($field->custom) { + # Restore the obsolete value that got stashed earlier (in memory) + $field->set_obsolete($original_obsolete); + + my $name = $field->name; + my $type = $field->type; + if (SQL_DEFINITIONS->{$type}) { + # Create the database column that stores the data for this field. + $dbh->bz_add_column('bugs', $name, SQL_DEFINITIONS->{$type}); + } + + if ($field->is_select) { + # Create the table that holds the legal values for this field. + $dbh->bz_add_field_tables($field); + } + + if ($type == FIELD_TYPE_SINGLE_SELECT) { + # Insert a default value of "---" into the legal values table. + $dbh->do("INSERT INTO $name (value) VALUES ('---')"); + } + + # Safe to write the original 'obsolete' value to the database now + $field->update; } + }; + + my $error = "$@"; + if ($params->{'custom'}) { + SetParam('disable_bug_updates', 0); + write_params(); } + die $error if $error; + + Bugzilla::Hook::process("field_end_of_create", { field => $field }); return $field; } diff --git a/Bugzilla/Group.pm b/Bugzilla/Group.pm index b7532fe09..3f521d0f2 100644 --- a/Bugzilla/Group.pm +++ b/Bugzilla/Group.pm @@ -119,9 +119,10 @@ sub _get_members { } sub flag_types { - my $self = shift; + my ($self, $params) = @_; + $params ||= {}; require Bugzilla::FlagType; - $self->{flag_types} ||= Bugzilla::FlagType::match({ group => $self->id }); + $self->{flag_types} ||= Bugzilla::FlagType::match({ group => $self->id, %$params }); return $self->{flag_types}; } diff --git a/Bugzilla/Install.pm b/Bugzilla/Install.pm index ce8fe6bad..60e96766b 100644 --- a/Bugzilla/Install.pm +++ b/Bugzilla/Install.pm @@ -93,6 +93,8 @@ sub SETTINGS { # 2011-06-21 glob@mozilla.com -- Bug 589128 email_format => { options => ['html', 'text_only'], default => 'html' }, + # 2011-06-16 glob@mozilla.com -- Bug 663747 + bugmail_new_prefix => { options => ['on', 'off'], default => 'on' }, } }; diff --git a/Bugzilla/Install/DB.pm b/Bugzilla/Install/DB.pm index 5ce3c7a4e..f30e1503b 100644 --- a/Bugzilla/Install/DB.pm +++ b/Bugzilla/Install/DB.pm @@ -637,6 +637,9 @@ sub update_table_definitions { # 2009-05-07 ghendricks@novell.com - Bug 77193 _add_isactive_to_product_fields(); + # 2009-05-07 ghendricks@novell.com - Bug 77193 + _add_isactive_to_product_fields(); + # 2010-10-09 LpSolit@gmail.com - Bug 505165 $dbh->bz_alter_column('flags', 'setter_id', {TYPE => 'INT3', NOTNULL => 1}); @@ -3207,6 +3210,11 @@ sub _populate_bugs_fulltext { print "Populating bugs_fulltext with $num_bugs entries..."; print " (this can take a long time.)\n"; } + + # As recommended by Monty Widenius for GNOME's upgrade. + # mkanat and justdave concur it'll be helpful for bmo, too. + $dbh->do('SET SESSION myisam_sort_buffer_size = 3221225472'); + my $newline = $dbh->quote("\n"); $dbh->do( qq{$command INTO bugs_fulltext (bug_id, short_desc, comments, @@ -3602,6 +3610,26 @@ sub _rename_tags_to_tag { } } +sub _add_isactive_to_product_fields { + my $dbh = Bugzilla->dbh; + + # If we add the isactive column all values should start off as active + if (!$dbh->bz_column_info('components', 'isactive')) { + $dbh->bz_add_column('components', 'isactive', + {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'TRUE'}); + } + + if (!$dbh->bz_column_info('versions', 'isactive')) { + $dbh->bz_add_column('versions', 'isactive', + {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'TRUE'}); + } + + if (!$dbh->bz_column_info('milestones', 'isactive')) { + $dbh->bz_add_column('milestones', 'isactive', + {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'TRUE'}); + } +} + 1; __END__ diff --git a/Bugzilla/Install/Filesystem.pm b/Bugzilla/Install/Filesystem.pm index 15106dab9..e6783bbee 100644 --- a/Bugzilla/Install/Filesystem.pm +++ b/Bugzilla/Install/Filesystem.pm @@ -169,6 +169,7 @@ sub FILESYSTEM { 'contrib/README' => { perms => OWNER_WRITE }, 'contrib/*/README' => { perms => OWNER_WRITE }, + 'contrib/sendunsentbugmail.pl' => { perms => WS_EXECUTE }, 'docs/bugzilla.ent' => { perms => OWNER_WRITE }, 'docs/makedocs.pl' => { perms => OWNER_EXECUTE }, 'docs/style.css' => { perms => WS_SERVE }, @@ -183,8 +184,10 @@ sub FILESYSTEM { # Directories that we want to set the perms on, but not # recurse through. These are directories we didn't create # in checkesetup.pl. + # + # Purpose of BMO change: unknown. my %non_recurse_dirs = ( - '.' => DIR_WS_SERVE, + '.' => 0755, docs => DIR_WS_SERVE, ); @@ -242,10 +245,13 @@ sub FILESYSTEM { dirs => DIR_WS_SERVE }, "$extensionsdir/*/web" => { files => WS_SERVE, dirs => DIR_WS_SERVE }, - + + # Purpose: allow webserver to read .bzr so we execute bzr commands + # in backticks and look at the result over the web. Used to show + # bzr history. + '.bzr' => { files => WS_SERVE, + dirs => DIR_WS_SERVE }, # Directories only for the owner, not for the webserver. - '.bzr' => { files => OWNER_WRITE, - dirs => DIR_OWNER_WRITE }, t => { files => OWNER_WRITE, dirs => DIR_OWNER_WRITE }, xt => { files => OWNER_WRITE, diff --git a/Bugzilla/Product.pm b/Bugzilla/Product.pm index a0079a033..976804cb0 100644 --- a/Bugzilla/Product.pm +++ b/Bugzilla/Product.pm @@ -779,7 +779,8 @@ sub user_has_access { } sub flag_types { - my $self = shift; + my ($self, $params) = @_; + $params ||= {}; return $self->{'flag_types'} if defined $self->{'flag_types'}; @@ -787,7 +788,7 @@ sub flag_types { my $cache = Bugzilla->request_cache->{flag_types_per_product} ||= {}; $self->{flag_types} = {}; my $prod_id = $self->id; - my $flagtypes = Bugzilla::FlagType::match({ product_id => $prod_id }); + my $flagtypes = Bugzilla::FlagType::match({ product_id => $prod_id, %$params }); foreach my $type ('bug', 'attachment') { my @flags = grep { $_->target_type eq $type } @$flagtypes; diff --git a/Bugzilla/Search.pm b/Bugzilla/Search.pm index d47e0ae99..a1378e540 100644 --- a/Bugzilla/Search.pm +++ b/Bugzilla/Search.pm @@ -2786,7 +2786,8 @@ sub _changedby { sub IsValidQueryType { my ($queryType) = @_; - if (grep { $_ eq $queryType } qw(specific advanced)) { + # BMO: Added google query type + if (grep { $_ eq $queryType } qw(specific advanced google)) { return 1; } return 0; diff --git a/Bugzilla/Search/Quicksearch.pm b/Bugzilla/Search/Quicksearch.pm index 8425a2be2..1d332e5ae 100644 --- a/Bugzilla/Search/Quicksearch.pm +++ b/Bugzilla/Search/Quicksearch.pm @@ -492,6 +492,9 @@ sub _default_quicksearch_word { addChart('short_desc', 'substring', $word, $negate); addChart('status_whiteboard', 'substring', $word, $negate); addChart('content', 'matches', _matches_phrase($word), $negate) if $fulltext; + + # BMO Bug 664124 - Include the crash signature (sig:) field in default quicksearches + addChart('cf_crash_signature', 'substring', $word, $negate); } sub _handle_urls { diff --git a/Bugzilla/Template.pm b/Bugzilla/Template.pm index 527b704b2..433b283b2 100644 --- a/Bugzilla/Template.pm +++ b/Bugzilla/Template.pm @@ -234,7 +234,8 @@ sub quoteUrls { ~<a href=\"mailto:$2\">$1$2</a>~igx; # attachment links - $text =~ s~\b(attachment\s*\#?\s*(\d+)(?:\s+\[details\])?) + # BMO: Bug 652332 dkl@mozilla.com 2011-07-20 + $text =~ s~\b(attachment\s*\#?\s*(\d+)(?:\s+\[diff\])?(?:\s+\[details\])?) ~($things[$count++] = get_attachment_link($2, $1)) && ("\0\0" . ($count-1) . "\0\0") ~egmxi; @@ -293,18 +294,20 @@ sub get_attachment_link { $title = html_quote(clean_text($title)); $link_text =~ s/ \[details\]$//; + $link_text =~ s/ \[diff\]$//; my $linkval = "attachment.cgi?id=$attachid"; - # If the attachment is a patch, try to link to the diff rather - # than the text, by default. + # If the attachment is a patch and patch_viewer feature is + # enabled, add link to the diff. my $patchlink = ""; if ($attachment->ispatch and Bugzilla->feature('patch_viewer')) { - $patchlink = '&action=diff'; + $patchlink = qq| <a href="${linkval}&action=diff" title="$title">[diff]</a>|; } # Whitespace matters here because these links are in <pre> tags. return qq|<span class="$className">| - . qq|<a href="${linkval}${patchlink}" name="attach_${attachid}" title="$title">$link_text</a>| + . qq|<a href="${linkval}" name="attach_${attachid}" title="$title">$link_text</a>| + . qq|${patchlink}| . qq| <a href="${linkval}&action=edit" title="$title">[details]</a>| . qq|</span>|; } diff --git a/Bugzilla/Token.pm b/Bugzilla/Token.pm index 86220aa29..4e32436c0 100644 --- a/Bugzilla/Token.pm +++ b/Bugzilla/Token.pm @@ -109,6 +109,8 @@ sub IssueEmailChangeToken { $vars->{'newemailaddress'} = $new_email . $email_suffix; $vars->{'expiration_ts'} = ctime($token_ts + MAX_TOKEN_AGE * 86400); $vars->{'token'} = $token; + # For SecureMail extension + $vars->{'to_user'} = $user; $vars->{'emailaddress'} = $old_email . $email_suffix; my $message; diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm index ea186a0fd..8ad84cec7 100644 --- a/Bugzilla/User.pm +++ b/Bugzilla/User.pm @@ -50,6 +50,7 @@ use Bugzilla::Product; use Bugzilla::Classification; use Bugzilla::Field; use Bugzilla::Group; +use Bugzilla::Hook; use DateTime::TimeZone; use List::Util qw(max); @@ -708,8 +709,8 @@ sub bless_groups { return $self->{'bless_groups'} if defined $self->{'bless_groups'}; return [] unless $self->id; - if ($self->in_group('editusers')) { - # Users having editusers permissions may bless all groups. + if ($self->in_group('admin')) { + # Users having admin permissions may bless all groups. $self->{'bless_groups'} = [Bugzilla::Group->get_all]; return $self->{'bless_groups'}; } @@ -2293,7 +2294,7 @@ Determines whether or not a user is in the given group by id. Returns an arrayref of L<Bugzilla::Group> objects. The arrayref consists of the groups the user can bless, taking into account -that having editusers permissions means that you can bless all groups, and +that having admin permissions means that you can bless all groups, and that you need to be able to see a group in order to bless it. =item C<get_products_by_permission($group)> diff --git a/Bugzilla/WebService/Bug.pm b/Bugzilla/WebService/Bug.pm index fb2b7b65d..c2083a59f 100644 --- a/Bugzilla/WebService/Bug.pm +++ b/Bugzilla/WebService/Bug.pm @@ -439,10 +439,17 @@ sub search { delete $match_params{'include_fields'}; delete $match_params{'exclude_fields'}; + my $count_only = delete $match_params{count_only}; + my $bugs = Bugzilla::Bug->match(\%match_params); my $visible = Bugzilla->user->visible_bugs($bugs); - my @hashes = map { $self->_bug_to_hash($_, $params) } @$visible; - return { bugs => \@hashes }; + if ($count_only) { + return { bug_count => scalar @$visible }; + } + else { + my @hashes = map { $self->_bug_to_hash($_, $params) } @$visible; + return { bugs => \@hashes }; + } } sub possible_duplicates { @@ -469,6 +476,12 @@ sub possible_duplicates { sub update { my ($self, $params) = validate(@_, 'ids'); + # BMO: Don't allow updating of bugs if disabled + if (Bugzilla->params->{disable_bug_updates}) { + ThrowErrorPage('bug/process/updates-disabled.html.tmpl', + 'Bug updates are currently disabled.'); + } + my $user = Bugzilla->login(LOGIN_REQUIRED); my $dbh = Bugzilla->dbh; @@ -563,6 +576,13 @@ sub update { sub create { my ($self, $params) = @_; + + # BMO: Don't allow updating of bugs if disabled + if (Bugzilla->params->{disable_bug_updates}) { + ThrowErrorPage('bug/process/updates-disabled.html.tmpl', + 'Bug updates are currently disabled.'); + } + Bugzilla->login(LOGIN_REQUIRED); $params = Bugzilla::Bug::map_fields($params); my $bug = Bugzilla::Bug->create($params); @@ -625,6 +645,12 @@ sub add_attachment { my ($self, $params) = validate(@_, 'ids'); my $dbh = Bugzilla->dbh; + # BMO: Don't allow updating of bugs if disabled + if (Bugzilla->params->{disable_bug_updates}) { + ThrowErrorPage('bug/process/updates-disabled.html.tmpl', + 'Bug updates are currently disabled.'); + } + Bugzilla->login(LOGIN_REQUIRED); defined $params->{ids} || ThrowCodeError('param_required', { param => 'ids' }); @@ -670,6 +696,12 @@ sub add_attachment { sub add_comment { my ($self, $params) = @_; + # BMO: Don't allow updating of bugs if disabled + if (Bugzilla->params->{disable_bug_updates}) { + ThrowErrorPage('bug/process/updates-disabled.html.tmpl', + 'Bug updates are currently disabled.'); + } + #The user must login in order add a comment Bugzilla->login(LOGIN_REQUIRED); @@ -714,6 +746,12 @@ sub add_comment { sub update_see_also { my ($self, $params) = @_; + # BMO: Don't allow updating of bugs if disabled + if (Bugzilla->params->{disable_bug_updates}) { + ThrowErrorPage('bug/process/updates-disabled.html.tmpl', + 'Bug updates are currently disabled.'); + } + my $user = Bugzilla->login(LOGIN_REQUIRED); # Check parameters @@ -2160,6 +2198,11 @@ C<string> Search the "Status Whiteboard" field on bugs for a substring. Works the same as the C<summary> field described above, but searches the Status Whiteboard field. +=item C<count_only> + +C<boolean> If count_only set to true, only a single hash key called C<bug_count> +will be returned which is the number of bugs that matched the search. + =back =item B<Returns> diff --git a/Bugzilla/WebService/User.pm b/Bugzilla/WebService/User.pm index 2d9276cc3..984f41c8a 100644 --- a/Bugzilla/WebService/User.pm +++ b/Bugzilla/WebService/User.pm @@ -30,6 +30,7 @@ use Bugzilla::User; use Bugzilla::Util qw(trim); use Bugzilla::Token; use Bugzilla::WebService::Util qw(filter validate); +use Bugzilla::Hook; # Don't need auth to login use constant LOGIN_EXEMPT => { @@ -235,6 +236,9 @@ sub get { }} @$in_group; } + Bugzilla::Hook::process('webservice_user_get', + { webservice => $self, params => $params, users => \@users }); + return { users => \@users }; } diff --git a/attachment.cgi b/attachment.cgi index 5eba13611..9fec1b2bd 100755 --- a/attachment.cgi +++ b/attachment.cgi @@ -76,6 +76,12 @@ local our $vars = {}; my $action = $cgi->param('action') || 'view'; my $format = $cgi->param('format') || ''; +# BMO: Don't allow updating of bugs if disabled +if (Bugzilla->params->{disable_bug_updates} && $cgi->request_method eq 'POST') { + ThrowErrorPage('bug/process/updates-disabled.html.tmpl', + 'Bug updates are currently disabled.'); +} + # You must use the appropriate urlbase/sslbase param when doing anything # but viewing an attachment, or a raw diff. if ($action ne 'view' @@ -497,7 +503,8 @@ sub enter { my $flag_types = Bugzilla::FlagType::match({'target_type' => 'attachment', 'product_id' => $bug->product_id, - 'component_id' => $bug->component_id}); + 'component_id' => $bug->component_id, + 'is_active' => 1}); $vars->{'flag_types'} = $flag_types; $vars->{'any_flags_requesteeble'} = grep { $_->is_requestable && $_->is_requesteeble } @$flag_types; diff --git a/bzr-update.sh b/bzr-update.sh new file mode 100644 index 000000000..e1d88e5d7 --- /dev/null +++ b/bzr-update.sh @@ -0,0 +1,9 @@ +#!/bin/bash +HOST=`hostname -s` +TAG="current-staging" +[ "$HOST" == "mradm02" -o "$HOST" == "ip-admin02" ] && TAG="current-production" +echo "+ bzr pull --overwrite -rtag:$TAG" +output=`bzr pull --overwrite -rtag:$TAG 2>&1` +echo "$output" +echo "$output" | grep "Now on revision" | sed -e 's/Now on revision //' -e 's/\.$//' | xargs -i{} echo bzr pull --overwrite -r{} \# `date` >> `dirname $0`/cvs-update.log +contrib/fixperms.pl @@ -274,7 +274,8 @@ sub assertCanCreate { # Check permission for frequency my $min_freq = 7; - if ($cgi->param('frequency') < $min_freq && !$user->in_group("admin")) { + # Upstreaming: denied, as this min_freq feature is going away. + if ($cgi->param('frequency') < $min_freq && !$user->in_group("bz_canusewhines")) { ThrowUserError("illegal_frequency", { 'minimum' => $min_freq }); } } diff --git a/contrib/addcustomfield.pl b/contrib/addcustomfield.pl new file mode 100644 index 000000000..c7f93c297 --- /dev/null +++ b/contrib/addcustomfield.pl @@ -0,0 +1,62 @@ +#!/usr/bin/perl -wT +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# Contributor(s): Frédéric Buclin <LpSolit@gmail.com> +# David Miller <justdave@mozilla.com> + +use strict; +use lib qw(. lib); + +use Bugzilla; +use Bugzilla::Constants; +use Bugzilla::Field; + +Bugzilla->usage_mode(USAGE_MODE_CMDLINE); + +my %types = ( + 'freetext' => FIELD_TYPE_FREETEXT, + 'single_select' => FIELD_TYPE_SINGLE_SELECT, + 'multi_select' => FIELD_TYPE_MULTI_SELECT, + 'textarea' => FIELD_TYPE_TEXTAREA, + 'datetime' => FIELD_TYPE_DATETIME, + 'bug_id' => FIELD_TYPE_BUG_ID, + 'bug_urls' => FIELD_TYPE_BUG_URLS, + 'keywords' => FIELD_TYPE_KEYWORDS, +); + +my $syntax = + "syntax: addcustomfield.pl <field name> [field type]\n\n" . + "valid field types:\n " . join("\n ", sort keys %types) . "\n\n" . + "the default field type is single_select\n"; + +my $name = shift || die $syntax; +my $type = lc(shift || 'single_select'); +exists $types{$type} || die "Invalid field type '$type'.\n\n$syntax"; +$type = $types{$type}; + +Bugzilla::Field->create({ + name => $name, + description => 'Please give me a description!', + type => $type, + mailhead => 0, + enter_bug => 0, + obsolete => 1, + custom => 1, + buglist => 1, +}); +print "Done!\n"; + +my $urlbase = Bugzilla->params->{urlbase}; +print "Please visit ${urlbase}editfields.cgi?action=edit&name=$name to finish setting up this field.\n"; diff --git a/contrib/fix_comment_text.pl b/contrib/fix_comment_text.pl new file mode 100644 index 000000000..f17bbc3d4 --- /dev/null +++ b/contrib/fix_comment_text.pl @@ -0,0 +1,75 @@ +#!/usr/bin/perl +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Initial Developer of the Original Code is Mozilla Foundation +# Portions created by the Initial Developer are Copyright (C) 2011 the +# Initial Developer. All Rights Reserved. +# +#=============================================================================== +# +# FILE: fix_comment_text.pl +# +# USAGE: ./fix_comment_text.pl <comment_id> +# +# DESCRIPTION: Updates a comment in Bugzilla with the text after __DATA__ +# +# OPTIONS: <comment_id> - The comment id from longdescs with the comment +# to be replaced. +# REQUIREMENTS: --- +# BUGS: --- +# NOTES: --- +# AUTHOR: David Lawrence (:dkl), dkl@mozilla.com +# COMPANY: Mozilla Foundation +# VERSION: 1.0 +# CREATED: 06/20/2011 03:40:22 PM +# REVISION: --- +#=============================================================================== + +use strict; +use warnings; + +use lib "."; + +use Bugzilla; +use Bugzilla::Util qw(detaint_natural); + +my $comment_id = shift; + +if (!detaint_natural($comment_id)) { + print "Error: invalid comment id or comment id not provided.\n" . + "Usage: ./fix_comment_text.pl <comment_id>\n"; + exit(1); +} + +my $dbh = Bugzilla->dbh; + +my $comment = join("", <DATA>); + +if ($comment =~ /ENTER NEW COMMENT TEXT HERE/) { + print "Please enter the new comment text in the script " . + "after the __DATA__ marker.\n"; + exit(1); +} + +$dbh->bz_start_transaction; + +Bugzilla->dbh->do( + "UPDATE longdescs SET thetext = ? WHERE comment_id = ?", + undef, $comment, $comment_id); + +$dbh->bz_commit_transaction; + +exit(0); + +__DATA__ +ENTER NEW COMMENT TEXT HERE BELOW THE __DATA__ MARKER! diff --git a/contrib/moco-ldap-check.pl b/contrib/moco-ldap-check.pl new file mode 100644 index 000000000..59f515bf2 --- /dev/null +++ b/contrib/moco-ldap-check.pl @@ -0,0 +1,224 @@ +#!/usr/bin/perl -wT +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# The Initial Developer of the Original Code is the Mozilla +# Foundation. Portions created by Mozilla are +# Copyright (C) 2011 Mozilla Foundation. All Rights Reserved. +# +# Contributor(s): Byron Jones <glob@mozilla.com> + +use strict; + +use lib qw(.); + +use Net::LDAP; +use XMLRPC::Lite; +use HTTP::Cookies; +use LWP::UserAgent; +use Term::ReadKey; +$| = 1; + +# +# +# + +print STDERR <<EOF; +This script cross-checks members of the Bugzilla mozilla-corporation group +with Mozilla's LDAP repository. + +To run this script you need: + - a bugzilla.mozilla.org admin account + - a Mozilla LDAP account + +EOF + +my $bugzillaLogin = get_text('bl', 'Bugzilla Login: '); +my $bugzillaPassword = get_text('bp', 'Bugzilla Password: ', 1); +my $ldapLogin = get_text('ll', 'LDAP Login: '); +my $ldapPassword = get_text('lp', 'LDAP Password: ', 1); + +sub get_text { + my($switch, $prompt, $password) = @_; + + for (my $i = 0; $i <= $#ARGV; $i++) { + if ($ARGV[$i] eq "-$switch") { + return $ARGV[$i + 1]; + } + } + + print STDERR $prompt; + my $response = ''; + ReadMode 4; + my $ch; + while(1) { + 1 while (not defined ($ch = ReadKey(-1))); + exit if $ch eq "\3"; + last if $ch =~ /[\r\n]/; + if ($ch =~ /[\b\x7F]/) { + next if $response eq ''; + chop $response; + print "\b \b"; + next; + } + if ($ch eq "\025") { + my $len = length($response); + print(("\b" x $len) . (" " x $len) . ("\b" x $len)); + $response = ''; + next; + } + next if ord($ch) < 32; + $response .= $ch; + print STDERR $password ? '*' : $ch; + } + ReadMode 0; + print STDERR "\n"; + return $response; +} +END { + ReadMode 0; +} + +# +# get list of users in mo-co group +# + +my %bugzilla; +{ + my $cookie_jar = HTTP::Cookies->new(file => "cookies.txt", autosave => 1); + my $proxy = XMLRPC::Lite->proxy( + 'https://bugzilla.mozilla.org/xmlrpc.cgi', + 'cookie_jar' => $cookie_jar); + my $response; + + print STDERR "Logging in to Bugzilla...\n"; + $response = $proxy->call( + 'User.login', + { + login => $bugzillaLogin, + password => $bugzillaPassword, + remember => 1, + } + ); + if ($response->fault) { + my ($package, $filename, $line) = caller; + die $response->faultstring . "\n"; + } + + my $ua = LWP::UserAgent->new(); + $ua->cookie_jar($cookie_jar); + $response = $ua->get('https://bugzilla.mozilla.org/editusers.cgi?' . + 'action=list&matchvalue=login_name&matchstr=&matchtype=substr&' . + 'grouprestrict=1&groupid=42'); + if (!$response->is_success) { + die $response->status_line; + } + + print STDERR "Getting user list from Bugzilla...\n"; + my $content = $response->content; + while ( + $content =~ m# + <td([^>]*)>[^<]+ + <a\shref="editusers[^"]+">([^<]+)</a>[^<]+ + </td>[^<]+ + <td[^>]*>([^<]+)</td> + #gx + ) { + my ($class, $email, $name) = ($1, $2, $3); + next if $class =~ /bz_inactive/; + $email =~ s/(^\s+|\s+$)//g; + $email =~ s/@/@/; + next unless $email =~ /@/; + $name =~ s/(^\s+|\s+$)//g; + $bugzilla{lc $email} = $name; + } +} + +# +# build list of current mo-co bugmail accounts +# + +my %ldap; +{ + print STDERR "Logging into LDAP...\n"; + my $ldap = Net::LDAP->new('addressbook.mozilla.com', + scheme => 'ldaps', onerror => 'die') or die "$@"; + $ldap->bind("mail=$ldapLogin,o=com,dc=mozilla", password => $ldapPassword); + my $result = $ldap->search( + base => 'o=com,dc=mozilla', + scope => 'sub', + filter => '(mail=*)', + attrs => ['mail', 'bugzillaEmail', 'emailAlias', 'cn', 'employeeType'], + ); + print STDERR "Getting user list from LDAP...\n"; + foreach my $entry ($result->entries) { + my ($name, $bugMail, $mail, $type) = + map { $entry->get_value($_) || '' } + qw(cn bugzillaEmail mail employeeType); + next if $type eq 'DISABLED'; + $mail = lc $mail; + $ldap{$mail}{name} = $name; + $ldap{$mail}{bugMail} = lc $bugMail; + $ldap{$mail}{alias} = {}; + foreach my $alias ( + @{$entry->get_value('emailAlias', asref => 1) || []} + ) { + $ldap{$mail}{alias}{lc $alias} = 1; + } + } +} + +# +# cross-check +# + +my @invalid; +foreach my $bugzilla (sort keys %bugzilla) { + # check for matching bugmail entry + my $exists = 0; + foreach my $mail (sort keys %ldap) { + next unless $ldap{$mail}{bugMail} eq $bugzilla; + $exists = 1; + last; + } + next if $exists; + + # check for matching mail + $exists = 0; + foreach my $mail (sort keys %ldap) { + next unless $mail eq $bugzilla; + $exists = 1; + last; + } + next if $exists; + + # check for matching email alias + $exists = 0; + foreach my $mail (sort keys %ldap) { + next unless exists $ldap{$mail}{alias}{$bugzilla}; + $exists = 1; + last; + } + next if $exists; + + push @invalid, $bugzilla; +} + +my $max_length = 0; +foreach my $email (@invalid) { + $max_length = length($email) if length($email) > $max_length; +} +foreach my $email (@invalid) { + printf "%-${max_length}s %s\n", $email, $bugzilla{$email}; +} diff --git a/contrib/reorg-tools/README b/contrib/reorg-tools/README new file mode 100644 index 000000000..4e5d6eb4d --- /dev/null +++ b/contrib/reorg-tools/README @@ -0,0 +1,9 @@ +Upstreaming attempt: https://bugzilla.mozilla.org/show_bug.cgi?id=616499 + +Included in this directory is a group of tools we've used for moving components +around in a Bugzilla 3.2 install on bugzilla.mozilla.org. + +They may require tweaking if you use them on your own install. Putting them +here to make it easier to collaborate on them and keep them up-to-date. +Hopefully Bugzilla upstream will be able to just do this from the web UI +eventually. diff --git a/contrib/reorg-tools/bmo-plan.txt b/contrib/reorg-tools/bmo-plan.txt new file mode 100644 index 000000000..838ff0ab9 --- /dev/null +++ b/contrib/reorg-tools/bmo-plan.txt @@ -0,0 +1,82 @@ +==BMO Reorg Plan== + +Do the following things, mostly in order (but see "Timing" at the end): + +1) Create new classifications using GUI: + Graveyard (Description: "Old, retired products", sort key: <last>) + +2) Rename classifications using GUI: + Client Support to Other + +3) Move products between classification using GUI: + Grendel from Client Software to Graveyard + CCK from Unclassified to Graveyard + Derivatives from Unclassified to Graveyard + MozillaClassic from Unclassified to Graveyard + UI: "reclassify" link from the top-level classification list + +4) Create new products using GUI: + Core Graveyard in Graveyard + (desc: "Old, retired Core components", closed for entry, no charts) + MailNews Core in Components + (desc: "Mail and news components common to Thunderbird and SeaMonkey", + open for bug entry, create charts) + +5) Rename products using GUI, and fix queries using fixqueries.pl: +mysql> update series_categories set name="SeaMonkey (2)" where id=32; + Mozilla Application Suite to SeaMonkey + Sumo to support.mozilla.com + +5.5) Rename versions and milestones in Toolkit to match Firefox before step 6 + +6) Sync milestones, versions and groups between products using +syncmsandversions.pl: + Core -> Core Graveyard (new) + Core -> MailNews Core (new) + Firefox -> Toolkit + Core -> SeaMonkey + mozilla.org -> Websites (only 1) + +6.5) Sync flag inclusions using syncflags.pl: + Core -> Core Graveyard (new) + Core -> MailNews Core (new) + Core -> SeaMonkey + mozilla.org -> Websites (only 1) + +6.7) Allow Firefox flags temporarily in Toolkit: + 250 | blocking-firefox3 | blocking1.9 - 387 + 419 | blocking-firefox3.1 | blocking1.9.1 - 416 + 63 | blocking0.8 | blocking1.6 - 69 + 76 | blocking0.9 | blocking1.7 - 83 + 36 | review | review - 4 + 356 | wanted-firefox3 | wanted1.9 - 357 + 418 | wanted-firefox3.1 | wanted1.9.1 - 417 + +7) Move components using movecomponent.pl. + Any instruction beginning "moved from". + Can't fix the queries for this - oh well + <Very long list> + +8) Rename components using GUI, and fix queries using fixqueries.pl. + Any instruction beginning "renamed from" or "MailNews: prefix removed". + <Long list> + +9) Create new components using GUI. + Any instruction beginning "new". + <Long list> + +10) Move open bugs using GUI: + XP Miscellany to Core/General + +11) Merge components by moving bugs using GUI: + Any instruction beginning "merge in". + Merge all bugs, including closed. Delete empty component when done. + <long list of merges> + +12) Close Core Graveyard (and Grendel if necessary) to new bugs + +13) Rename Toolkit versions and milestones back (from 5.5) + +14) Execute flag mapping SQL using Reed's mapping to update bugs in Toolkit + +15) Disable above-listed flags in point 6.7 in Toolkit again diff --git a/contrib/reorg-tools/fixgroupqueries.pl b/contrib/reorg-tools/fixgroupqueries.pl new file mode 100644 index 000000000..1c75edb97 --- /dev/null +++ b/contrib/reorg-tools/fixgroupqueries.pl @@ -0,0 +1,119 @@ +#!/usr/bin/perl -w +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# The Initial Developer of the Original Code is Netscape Communications +# Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): Gervase Markham <gerv@gerv.net> + +use strict; + +use lib qw(. lib); + +use Bugzilla; +use Bugzilla::Constants; +use Bugzilla::Util; + +sub usage() { + print <<USAGE; +Usage: fixgroupqueries.pl <oldvalue> <newvalue> + +E.g.: fixgroupqueries.pl w-security webtools-security +will change all occurrences of "w-security" to "webtools-security" in the +appropriate places in the namedqueries. + +Note that all parameters are case-sensitive. +USAGE +} + +sub do_namedqueries($$) { + my ($old, $new) = @_; + $old = url_quote($old); + $new = url_quote($new); + + my $dbh = Bugzilla->dbh; + + my $replace_count = 0; + my $query = $dbh->selectall_arrayref("SELECT id, query FROM namedqueries"); + if ($query) { + my $sth = $dbh->prepare("UPDATE namedqueries SET query = ? + WHERE id = ?"); + + foreach my $row (@$query) { + my ($id, $query) = @$row; + if (($query =~ /field\d+-\d+-\d+=bug_group/) && + ($query =~ /(?:^|&|;)value\d+-\d+-\d+=$old(?:;|&|$)/)) { + $query =~ s/((?:^|&|;)value\d+-\d+-\d+=)$old(;|&|$)/$1$new$2/; + $sth->execute($query, $id); + $replace_count++; + } + } + } + + print "namedqueries: $replace_count replacements made.\n"; +} + +# series +sub do_series($$) { + my ($old, $new) = @_; + $old = url_quote($old); + $new = url_quote($new); + + my $dbh = Bugzilla->dbh; + #$dbh->bz_start_transaction(); + + my $replace_count = 0; + my $query = $dbh->selectall_arrayref("SELECT series_id, query + FROM series"); + if ($query) { + my $sth = $dbh->prepare("UPDATE series SET query = ? + WHERE series_id = ?"); + foreach my $row (@$query) { + my ($series_id, $query) = @$row; + + if (($query =~ /field\d+-\d+-\d+=bug_group/) && + ($query =~ /(?:^|&|;)value\d+-\d+-\d+=$old(?:;|&|$)/)) { + $query =~ s/((?:^|&|;)value\d+-\d+-\d+=)$old(;|&|$)/$1$new$2/; + $sth->execute($query, $series_id); + $replace_count++; + } + } + } + + #$dbh->bz_commit_transaction(); + print "series: $replace_count replacements made.\n"; +} + +############################################################################# +# MAIN CODE +############################################################################# +# This is a pure command line script. +Bugzilla->usage_mode(USAGE_MODE_CMDLINE); + +if (scalar @ARGV < 2) { + usage(); + exit(); +} + +my ($old, $new) = @ARGV; + +print "Changing all instances of '$old' to '$new'.\n\n"; + +#do_namedqueries($old, $new); +do_series($old, $new); + +exit(0); diff --git a/contrib/reorg-tools/fixqueries.pl b/contrib/reorg-tools/fixqueries.pl new file mode 100644 index 000000000..4b862fd72 --- /dev/null +++ b/contrib/reorg-tools/fixqueries.pl @@ -0,0 +1,132 @@ +#!/usr/bin/perl -w +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# The Initial Developer of the Original Code is Netscape Communications +# Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): Gervase Markham <gerv@gerv.net> + +use strict; + +use lib qw(. lib); + +use Bugzilla; +use Bugzilla::Constants; +use Bugzilla::Util; + +sub usage() { + print <<USAGE; +Usage: fixqueries.pl <parameter> <oldvalue> <newvalue> + +E.g.: fixqueries.pl product FoodReplicator SeaMonkey +will change all occurrences of "FoodReplicator" to "Seamonkey" in the +appropriate places in the namedqueries, series and series_categories tables. + +Note that all parameters are case-sensitive. +USAGE +} + +sub do_namedqueries($$$) { + my ($field, $old, $new) = @_; + $old = url_quote($old); + $new = url_quote($new); + + my $dbh = Bugzilla->dbh; + #$dbh->bz_start_transaction(); + + my $replace_count = 0; + my $query = $dbh->selectall_arrayref("SELECT id, query FROM namedqueries"); + if ($query) { + my $sth = $dbh->prepare("UPDATE namedqueries SET query = ? + WHERE id = ?"); + + foreach my $row (@$query) { + my ($id, $query) = @$row; + if ($query =~ /(?:^|&|;)$field=$old(?:&|$|;)/) { + $query =~ s/((?:^|&|;)$field=)$old(;|&|$)/$1$new$2/; + $sth->execute($query, $id); + $replace_count++; + } + } + } + + #$dbh->bz_commit_transaction(); + print "namedqueries: $replace_count replacements made.\n"; +} + +# series +sub do_series($$$) { + my ($field, $old, $new) = @_; + $old = url_quote($old); + $new = url_quote($new); + + my $dbh = Bugzilla->dbh; + #$dbh->bz_start_transaction(); + + my $replace_count = 0; + my $query = $dbh->selectall_arrayref("SELECT series_id, query + FROM series"); + if ($query) { + my $sth = $dbh->prepare("UPDATE series SET query = ? + WHERE series_id = ?"); + foreach my $row (@$query) { + my ($series_id, $query) = @$row; + + if ($query =~ /(?:^|&|;)$field=$old(?:&|$|;)/) { + $query =~ s/((?:^|&|;)$field=)$old(;|&|$)/$1$new$2/; + $replace_count++; + } + + $sth->execute($query, $series_id); + } + } + + #$dbh->bz_commit_transaction(); + print "series: $replace_count replacements made.\n"; +} + +# series_categories +sub do_series_categories($$) { + my ($old, $new) = @_; + my $dbh = Bugzilla->dbh; + + $dbh->do("UPDATE series_categories SET name = ? WHERE name = ?", + undef, + ($new, $old)); +} + +############################################################################# +# MAIN CODE +############################################################################# +# This is a pure command line script. +Bugzilla->usage_mode(USAGE_MODE_CMDLINE); + +if (scalar @ARGV < 3) { + usage(); + exit(); +} + +my ($field, $old, $new) = @ARGV; + +print "Changing all instances of '$old' to '$new'.\n\n"; + +do_namedqueries($field, $old, $new); +do_series($field, $old, $new); +do_series_categories($old, $new); + +exit(0); + diff --git a/contrib/reorg-tools/migrate_crash_signatures.pl b/contrib/reorg-tools/migrate_crash_signatures.pl new file mode 100644 index 000000000..b12446280 --- /dev/null +++ b/contrib/reorg-tools/migrate_crash_signatures.pl @@ -0,0 +1,126 @@ +#!/usr/bin/perl +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Initial Developer of the Original Code is Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2011 the +# Initial Developer. All Rights Reserved. +# +#=============================================================================== +# +# FILE: migrate_crash_signatures.pl +# +# USAGE: ./migrate_crash_signatures.pl +# +# DESCRIPTION: Migrate current summary data on matched bugs to the +# new cf_crash_signature custom fields. +# +# OPTIONS: No params, then performs dry-run without updating the database. +# If a true value is passed as single argument, then the database +# is updated. +# REQUIREMENTS: None +# BUGS: 577724 +# NOTES: None +# AUTHOR: David Lawrence (dkl@mozilla.com), +# COMPANY: Mozilla Corproation +# VERSION: 1.0 +# CREATED: 05/31/2011 03:57:52 PM +# REVISION: 1 +#=============================================================================== + +use strict; +use warnings; + +use lib qw(. lib); + +use Bugzilla; +use Bugzilla::Constants; +use Bugzilla::Util; + +use Data::Dumper; + +Bugzilla->usage_mode(USAGE_MODE_CMDLINE); + +my $UPDATE_DB = shift; # Pass true value as single argument to perform database update + +my $dbh = Bugzilla->dbh; + +# User to make changes as +my $user_id = $dbh->selectrow_array( + "SELECT userid FROM profiles WHERE login_name='nobody\@mozilla.org'"); +$user_id or die "Can't find user ID for 'nobody\@mozilla.org'\n"; + +my $field_id = $dbh->selectrow_array( + "SELECT id FROM fielddefs WHERE name = 'cf_crash_signature'"); +$field_id or die "Can't find field ID for 'cf_crash_signature' field\n"; + +# Search criteria +# a) crash or topcrash keyword, +# b) not have [notacrash] in whiteboard, +# c) have a properly formulated [@ ...] + +# crash and topcrash keyword ids +my $crash_keyword_id = $dbh->selectrow_array( + "SELECT id FROM keyworddefs WHERE name = 'crash'"); +$crash_keyword_id or die "Can't find keyword id for 'crash'\n"; + +my $topcrash_keyword_id = $dbh->selectrow_array( + "SELECT id FROM keyworddefs WHERE name = 'topcrash'"); +$topcrash_keyword_id or die "Can't find keyword id for 'topcrash'\n"; + +# main search query +my $bugs = $dbh->selectall_arrayref(" + SELECT bugs.bug_id, bugs.short_desc + FROM bugs LEFT JOIN keywords ON bugs.bug_id = keywords.bug_id + WHERE (keywords.keywordid = ? OR keywords.keywordid = ?) + AND bugs.status_whiteboard NOT REGEXP '\\\\[notacrash\\\\]' + AND bugs.short_desc REGEXP '\\\\[@.+\\\\]' + AND (bugs.cf_crash_signature IS NULL OR bugs.cf_crash_signature = '') + ORDER BY bugs.bug_id", + {'Slice' => {}}, $crash_keyword_id, $topcrash_keyword_id); + +my $bug_count = scalar @$bugs; +$bug_count or die "No bugs were found in matching search criteria.\n"; + +print "Migrating $bug_count bugs to new crash signature field\n"; + +$dbh->bz_start_transaction() if $UPDATE_DB; + +foreach my $bug (@$bugs) { + my $bug_id = $bug->{'bug_id'}; + my $summary = $bug->{'short_desc'}; + + print "Updating bug $bug_id ..."; + + my @signatures; + while ($summary =~ /(\[\@(?:\[.*\]|[^\[])*\])/g) { + push(@signatures, $1); + } + + if (@signatures && $UPDATE_DB) { + my $timestamp = $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)'); + $dbh->do("UPDATE bugs SET cf_crash_signature = ? WHERE bug_id = ?", + undef, join("\n", @signatures), $bug_id); + $dbh->do("INSERT INTO bugs_activity(bug_id, who, bug_when, fieldid, removed, added) " . + "VALUES (?, ?, ?, ?, '', ?)", + undef, $bug_id, $user_id, $timestamp, $field_id, join("\n", @signatures)); + $dbh->do("UPDATE bugs SET delta_ts = ?, lastdiffed = ? WHERE bug_id = ?", + undef, $timestamp, $timestamp, $bug_id); + } + elsif (@signatures) { + print Dumper(\@signatures); + } + + print "done.\n"; +} + +$dbh->bz_commit_transaction() if $UPDATE_DB; diff --git a/contrib/reorg-tools/move_flag_types.pl b/contrib/reorg-tools/move_flag_types.pl new file mode 100644 index 000000000..a75b7f497 --- /dev/null +++ b/contrib/reorg-tools/move_flag_types.pl @@ -0,0 +1,168 @@ +#!/usr/bin/perl +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Initial Developer of the Original Code is Mozilla Foundation +# Portions created by the Initial Developer are Copyright (C) 2011 the +# Initial Developer. All Rights Reserved. +# +#=============================================================================== +# +# FILE: move_flag_types.pl +# +# USAGE: ./move_flag_types.pl +# +# DESCRIPTION: Move current set flag from one type_id to another +# based on product and optionally component. +# +# OPTIONS: --- +# REQUIREMENTS: --- +# BUGS: --- +# NOTES: --- +# AUTHOR: David Lawrence (:dkl), dkl@mozilla.com +# COMPANY: Mozilla Foundation +# VERSION: 1.0 +# CREATED: 08/22/2011 05:18:06 PM +# REVISION: --- +#=============================================================================== + +=head1 NAME + +move_flag_types.pl - Move currently set flags from one type id to another based +on product and optionally component. + +=head1 SYNOPSIS + +This script will move bugs matching a specific product (and optionally a component) +from one flag type id to another if the bug has the flag set to either +, -, or ?. + +./move_flag_types.pl --old-id 4 --new-id 720 --product Firefox --component Installer + +=head1 OPTIONS + +=over + +=item B<--help|-h|?> + +Print a brief help message and exits. + +=item B<--oldid|-o> + +Old flag type id. Use editflagtypes.cgi to determine the type id from the URL. + +=item B<--newid|-n> + +New flag type id. Use editflagtypes.cgi to determine the type id from the URL. + +=item B<--product|-p> + +The product that the bugs most be assigned to. + +=item B<--component|-c> + +Optional: The component of the given product that the bugs must be assigned to. + +=item B<--doit|-d> + +Without this argument, changes are not actually committed to the database. + +=back + +=cut + +use strict; +use warnings; + +use lib '.'; + +use Bugzilla; +use Getopt::Long; +use Pod::Usage; + +my %params; +GetOptions(\%params, 'help|h|?', 'oldid|o=s', 'newid|n=s', + 'product|p=s', 'component|c:s', 'doit|d') or pod2usage(1); + +if ($params{'help'} || !$params{'oldid'} + || !$params{'newid'} || !$params{'product'}) { + pod2usage({ -message => "Missing required argument", + -exitval => 1 }); +} + +# Set defaults +$params{'doit'} ||= 0; +$params{'component'} ||= ''; + +my $dbh = Bugzilla->dbh; + +# Get the flag names +my $old_flag_name = $dbh->selectrow_array( + "SELECT name FROM flagtypes WHERE id = ?", + undef, $params{'oldid'}); +my $new_flag_name = $dbh->selectrow_array( + "SELECT name FROM flagtypes WHERE id = ?", + undef, $params{'newid'}); + +# Find the product id +my $product_id = $dbh->selectrow_array( + "SELECT id FROM products WHERE name = ?", + undef, $params{'product'}); + +# Find the component id if not __ANY__ +my $component_id; +if ($params{'component'}) { + $component_id = $dbh->selectrow_array( + "SELECT id FROM components WHERE name = ? AND product_id = ?", + undef, $params{'component'}, $product_id); +} + +my @query_args = ($params{'oldid'}); + +my $flag_query = "SELECT flags.id AS flag_id, flags.bug_id AS bug_id + FROM flags JOIN bugs ON flags.bug_id = bugs.bug_id + WHERE flags.type_id = ? "; + +if ($component_id) { + # No need to compare against product_id as component_id is already + # tied to a specific product + $flag_query .= "AND bugs.component_id = ?"; + push(@query_args, $component_id); +} +else { + # All bugs for a product regardless of component + $flag_query .= "AND bugs.product_id = ?"; + push(@query_args, $product_id); +} + +my $flags = $dbh->selectall_arrayref($flag_query, undef, @query_args); + +if (@$flags) { + print "Moving '" . scalar @$flags . "' flags " . + "from $old_flag_name (" . $params{'oldid'} . ") " . + "to $new_flag_name (" . $params{'newid'} . ")...\n"; + + if (!$params{'doit'}) { + print "Pass the argument --doit or -d to permanently make changes to the database.\n"; + } + else { + my $flag_update_sth = $dbh->prepare("UPDATE flags SET type_id = ? WHERE id = ?"); + + foreach my $flag (@$flags) { + my ($flag_id, $bug_id) = @$flag; + print "Bug: $bug_id Flag: $flag_id\n"; + $flag_update_sth->execute($params{'newid'}, $flag_id); + } + } +} +else { + print "No flags to move\n"; +} diff --git a/contrib/reorg-tools/movebugs.pl b/contrib/reorg-tools/movebugs.pl new file mode 100644 index 000000000..33156dad7 --- /dev/null +++ b/contrib/reorg-tools/movebugs.pl @@ -0,0 +1,151 @@ +#!/usr/bin/perl -w +use strict; + +use Cwd 'abs_path'; +use File::Basename; +BEGIN { + my $root = abs_path(dirname(__FILE__) . '/../..'); + chdir($root); +} +use lib qw(. lib); + +use Bugzilla; +use Bugzilla::Constants; +use Bugzilla::Util; + +Bugzilla->usage_mode(USAGE_MODE_CMDLINE); + +if (scalar @ARGV < 4) { + die <<USAGE; +Usage: movebugs.pl <old-product> <old-component> <new-product> <new-component> + +Eg. movebugs.pl mozilla.org bmo bugzilla.mozilla.org admin +Will move all bugs in the mozilla.org:bmo component to the +bugzilla.mozilla.org:admin component. + +The new product must have matching versions and milestones from the old +product. +USAGE +} + +my ($old_product, $old_component, $new_product, $new_component) = @ARGV; + +my $dbh = Bugzilla->dbh; + +my $old_product_id = $dbh->selectrow_array( + "SELECT id FROM products WHERE name=?", + undef, $old_product); +$old_product_id + or die "Can't find product ID for '$old_product'.\n"; + +my $old_component_id = $dbh->selectrow_array( + "SELECT id FROM components WHERE name=? AND product_id=?", + undef, $old_component, $old_product_id); +$old_component_id + or die "Can't find component ID for '$old_component'.\n"; + +my $new_product_id = $dbh->selectrow_array( + "SELECT id FROM products WHERE name=?", + undef, $new_product); +$new_product_id + or die "Can't find product ID for '$new_product'.\n"; + +my $new_component_id = $dbh->selectrow_array( + "SELECT id FROM components WHERE name=? AND product_id=?", + undef, $new_component, $new_product_id); +$new_component_id + or die "Can't find component ID for '$new_component'.\n"; + +my $product_field_id = $dbh->selectrow_array( + "SELECT id FROM fielddefs WHERE name = 'product'"); +$product_field_id + or die "Can't find field ID for 'product' field\n"; +my $component_field_id = $dbh->selectrow_array( + "SELECT id FROM fielddefs WHERE name = 'component'"); +$component_field_id + or die "Can't find field ID for 'component' field\n"; + +my $user_id = $dbh->selectrow_array( + "SELECT userid FROM profiles WHERE login_name='nobody\@mozilla.org'"); +$user_id + or die "Can't find user ID for 'nobody\@mozilla.org'\n"; + +$dbh->bz_start_transaction(); + +# build list of bugs +my $ra_ids = $dbh->selectcol_arrayref( + "SELECT bug_id FROM bugs WHERE product_id=? AND component_id=?", + undef, $old_product_id, $old_component_id); +my $bug_count = scalar @$ra_ids; +$bug_count + or die "No bugs were found in '$old_component'\n"; +my $where_sql = 'bug_id IN (' . join(',', @$ra_ids) . ')'; + +# check versions +my @missing_versions; +my $ra_versions = $dbh->selectcol_arrayref( + "SELECT DISTINCT version FROM bugs WHERE $where_sql"); +foreach my $version (@$ra_versions) { + my $has_version = $dbh->selectrow_array( + "SELECT 1 FROM versions WHERE product_id=? AND value=?", + undef, $new_product_id, $version); + push @missing_versions, $version unless $has_version; +} + +# check milestones +my @missing_milestones; +my $ra_milestones = $dbh->selectcol_arrayref( + "SELECT DISTINCT target_milestone FROM bugs WHERE $where_sql"); +foreach my $milestone (@$ra_milestones) { + my $has_milestone = $dbh->selectrow_array( + "SELECT 1 FROM milestones WHERE product_id=? AND value=?", + undef, $new_product_id, $milestone); + push @missing_milestones, $milestone unless $has_milestone; +} + +my $missing_error = ''; +if (@missing_versions) { + $missing_error .= "'$new_product' is missing the following version(s):\n " . + join("\n ", @missing_versions) . "\n"; +} +if (@missing_milestones) { + $missing_error .= "'$new_product' is missing the following milestone(s):\n " . + join("\n ", @missing_milestones) . "\n"; +} +die $missing_error if $missing_error; + +# confirmation +print <<EOF; +About to move $bug_count bugs +From '$old_product' : '$old_component' +To '$new_product' : '$new_component' + +Press <Ctrl-C> to stop or <Enter> to continue... +EOF +getc(); + +print "Moving $bug_count bugs from $old_product:$old_component to $new_product:$new_component\n"; + +# update bugs +$dbh->do( + "UPDATE bugs SET product_id=?, component_id=? WHERE $where_sql", + undef, $new_product_id, $new_component_id); + +# touch bugs +$dbh->do("UPDATE bugs SET delta_ts=NOW() WHERE $where_sql"); +$dbh->do("UPDATE bugs SET lastdiffed=NOW() WHERE $where_sql"); + +# update bugs_activity +$dbh->do( + "INSERT INTO bugs_activity(bug_id, who, bug_when, fieldid, removed, added) + SELECT bug_id, ?, delta_ts, ?, ?, ? FROM bugs WHERE $where_sql", + undef, + $user_id, $product_field_id, $old_product, $new_product); +$dbh->do( + "INSERT INTO bugs_activity(bug_id, who, bug_when, fieldid, removed, added) + SELECT bug_id, ?, delta_ts, ?, ?, ? FROM bugs WHERE $where_sql", + undef, + $user_id, $component_field_id, $old_component, $new_component); + +$dbh->bz_commit_transaction(); + diff --git a/contrib/reorg-tools/movecomponent.pl b/contrib/reorg-tools/movecomponent.pl new file mode 100644 index 000000000..8f8bc0abc --- /dev/null +++ b/contrib/reorg-tools/movecomponent.pl @@ -0,0 +1,193 @@ +#!/usr/bin/perl -w +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# The Initial Developer of the Original Code is Netscape Communications +# Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): Gervase Markham <gerv@gerv.net> + +# See also https://bugzilla.mozilla.org/show_bug.cgi?id=119569 +# + +use strict; + +use Cwd 'abs_path'; +use File::Basename; +BEGIN { + my $root = abs_path(dirname(__FILE__) . '/../..'); + chdir($root); +} +use lib qw(. lib); + +use Bugzilla; +use Bugzilla::Constants; +use Bugzilla::Util; + +sub usage() { + print <<USAGE; +Usage: movecomponent.pl <oldproduct> <newproduct> <component> <doit> + +E.g.: movecomponent.pl ReplicationEngine FoodReplicator SeaMonkey +will move the component "SeaMonkey" from the product "ReplicationEngine" +to the product "FoodReplicator". + +Important: You must make sure the milestones and versions of the bugs in the +component are available in the new product. See syncmsandversions.pl. + +Pass in a true value for "doit" to make the database changes permament. +USAGE + + exit(1); +} + +############################################################################# +# MAIN CODE +############################################################################# + +# This is a pure command line script. +Bugzilla->usage_mode(USAGE_MODE_CMDLINE); + +if (scalar @ARGV < 3) { + usage(); + exit(); +} + +my ($oldproduct, $newproduct, $component, $doit) = @ARGV; + +my $dbh = Bugzilla->dbh; + +$dbh->{'AutoCommit'} = 0 unless $doit; # Turn off autocommit by default + +# Find product IDs +my $oldprodid = $dbh->selectrow_array("SELECT id FROM products WHERE name = ?", + undef, $oldproduct); +if (!$oldprodid) { + print "Can't find product ID for '$oldproduct'.\n"; + exit(1); +} + +my $newprodid = $dbh->selectrow_array("SELECT id FROM products WHERE name = ?", + undef, $newproduct); +if (!$newprodid) { + print "Can't find product ID for '$newproduct'.\n"; + exit(1); +} + +# Find component ID +my $compid = $dbh->selectrow_array("SELECT id FROM components + WHERE name = ? AND product_id = ?", + undef, $component, $oldprodid); +if (!$compid) { + print "Can't find component ID for '$component' in product " . + "'$oldproduct'.\n"; + exit(1); +} + +my $fieldid = $dbh->selectrow_array("SELECT id FROM fielddefs + WHERE name = 'product'"); +if (!$fieldid) { + print "Can't find field ID for 'product' field!\n"; + exit(1); +} + +# check versions +my @missing_versions; +my $ra_versions = $dbh->selectcol_arrayref( + "SELECT DISTINCT version FROM bugs WHERE component_id = ?", + undef, $compid); +foreach my $version (@$ra_versions) { + my $has_version = $dbh->selectrow_array( + "SELECT 1 FROM versions WHERE product_id = ? AND value = ?", + undef, $newprodid, $version); + push @missing_versions, $version unless $has_version; +} + +# check milestones +my @missing_milestones; +my $ra_milestones = $dbh->selectcol_arrayref( + "SELECT DISTINCT target_milestone FROM bugs WHERE component_id = ?", + undef, $compid); +foreach my $milestone (@$ra_milestones) { + my $has_milestone = $dbh->selectrow_array( + "SELECT 1 FROM milestones WHERE product_id=? AND value=?", + undef, $newprodid, $milestone); + push @missing_milestones, $milestone unless $has_milestone; +} + +my $missing_error = ''; +if (@missing_versions) { + $missing_error .= "'$newproduct' is missing the following version(s):\n " . + join("\n ", @missing_versions) . "\n"; +} +if (@missing_milestones) { + $missing_error .= "'$newproduct' is missing the following milestone(s):\n " . + join("\n ", @missing_milestones) . "\n"; +} +die $missing_error if $missing_error; + +# confirmation +print <<EOF; +About to move the component '$component' +From '$oldproduct' +To '$newproduct' + +Press <Ctrl-C> to stop or <Enter> to continue... +EOF +getc(); + +print "Moving '$component' from '$oldproduct' to '$newproduct'...\n\n"; +$dbh->bz_start_transaction() if $doit; + +# Bugs table +$dbh->do("UPDATE bugs SET product_id = ? WHERE component_id = ?", + undef, + ($newprodid, $compid)); + +# Flags tables +$dbh->do("UPDATE flaginclusions SET product_id = ? WHERE component_id = ?", + undef, + ($newprodid, $compid)); + +$dbh->do("UPDATE flagexclusions SET product_id = ? WHERE component_id = ?", + undef, + ($newprodid, $compid)); + +# Components +$dbh->do("UPDATE components SET product_id = ? WHERE id = ?", + undef, + ($newprodid, $compid)); + +# Mark bugs as touched +$dbh->do("UPDATE bugs SET delta_ts = NOW() + WHERE component_id = ?", undef, $compid); +$dbh->do("UPDATE bugs SET lastdiffed = NOW() + WHERE component_id = ?", undef, $compid); + +# Update bugs_activity +my $userid = 1; # nobody@mozilla.org + +$dbh->do("INSERT INTO bugs_activity(bug_id, who, bug_when, fieldid, removed, + added) + SELECT bug_id, ?, delta_ts, ?, ?, ? + FROM bugs WHERE component_id = ?", + undef, + ($userid, $fieldid, $oldproduct, $newproduct, $compid)); + +$dbh->bz_commit_transaction() if $doit; + +exit(0); + diff --git a/contrib/reorg-tools/syncflags.pl b/contrib/reorg-tools/syncflags.pl new file mode 100644 index 000000000..6c5b8293a --- /dev/null +++ b/contrib/reorg-tools/syncflags.pl @@ -0,0 +1,86 @@ +#!/usr/bin/perl -w +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# The Initial Developer of the Original Code is Netscape Communications +# Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): Gervase Markham <gerv@gerv.net> + +# See also https://bugzilla.mozilla.org/show_bug.cgi?id=119569 + +use strict; + +use lib qw(. lib); + +use Bugzilla; +use Bugzilla::Constants; + +sub usage() { + print <<USAGE; +Usage: syncflags.pl <srcproduct> <tgtproduct> + +E.g.: syncflags.pl FoodReplicator SeaMonkey +will copy any flag inclusions (only) for the product "FoodReplicator" +so matching inclusions exist for the product "SeaMonkey". This script is +normally used prior to moving components from srcproduct to tgtproduct. +USAGE + + exit(1); +} + +############################################################################# +# MAIN CODE +############################################################################# + +# This is a pure command line script. +Bugzilla->usage_mode(USAGE_MODE_CMDLINE); + +if (scalar @ARGV < 2) { + usage(); + exit(); +} + +my ($srcproduct, $tgtproduct) = @ARGV; + +my $dbh = Bugzilla->dbh; + +# Find product IDs +my $srcprodid = $dbh->selectrow_array("SELECT id FROM products WHERE name = ?", + undef, $srcproduct); +if (!$srcprodid) { + print "Can't find product ID for '$srcproduct'.\n"; + exit(1); +} + +my $tgtprodid = $dbh->selectrow_array("SELECT id FROM products WHERE name = ?", + undef, $tgtproduct); +if (!$tgtprodid) { + print "Can't find product ID for '$tgtproduct'.\n"; + exit(1); +} + +$dbh->do("INSERT INTO flaginclusions(component_id, type_id, product_id) + SELECT fi1.component_id, fi1.type_id, ? FROM flaginclusions fi1 + LEFT JOIN flaginclusions fi2 + ON fi1.type_id = fi2.type_id + AND fi2.product_id = ? + WHERE fi1.product_id = ? + AND fi2.type_id IS NULL", + undef, + $tgtprodid, $tgtprodid, $srcprodid); + +exit(0); diff --git a/contrib/reorg-tools/syncmsandversions.pl b/contrib/reorg-tools/syncmsandversions.pl new file mode 100644 index 000000000..b25b3348b --- /dev/null +++ b/contrib/reorg-tools/syncmsandversions.pl @@ -0,0 +1,107 @@ +#!/usr/bin/perl -w +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# The Initial Developer of the Original Code is Netscape Communications +# Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): Gervase Markham <gerv@gerv.net> + +# See also https://bugzilla.mozilla.org/show_bug.cgi?id=119569 + +use strict; + +use lib qw(. lib); + +use Bugzilla; +use Bugzilla::Constants; + +sub usage() { + print <<USAGE; +Usage: syncmsandversions.pl <srcproduct> <tgtproduct> + +E.g.: syncmsandversions.pl FoodReplicator SeaMonkey +will copy any versions and milstones in the product "FoodReplicator" +which do not exist in product "SeaMonkey" into it. This script is normally +used prior to moving components from srcproduct to tgtproduct. +USAGE + + exit(1); +} + +############################################################################# +# MAIN CODE +############################################################################# + +# This is a pure command line script. +Bugzilla->usage_mode(USAGE_MODE_CMDLINE); + +if (scalar @ARGV < 2) { + usage(); + exit(); +} + +my ($srcproduct, $tgtproduct) = @ARGV; + +my $dbh = Bugzilla->dbh; + +# Find product IDs +my $srcprodid = $dbh->selectrow_array("SELECT id FROM products WHERE name = ?", + undef, $srcproduct); +if (!$srcprodid) { + print "Can't find product ID for '$srcproduct'.\n"; + exit(1); +} + +my $tgtprodid = $dbh->selectrow_array("SELECT id FROM products WHERE name = ?", + undef, $tgtproduct); +if (!$tgtprodid) { + print "Can't find product ID for '$tgtproduct'.\n"; + exit(1); +} + +#$dbh->bz_start_transaction(); + +$dbh->do("INSERT INTO milestones(value, sortkey, product_id) + SELECT m1.value, m1.sortkey, ? FROM milestones m1 + LEFT JOIN milestones m2 ON m1.value = m2.value AND + m2.product_id = ? + WHERE m1.product_id = ? AND m2.value IS NULL", + undef, + $tgtprodid, $tgtprodid, $srcprodid); + +$dbh->do("INSERT INTO versions(value, product_id) + SELECT v1.value, ? FROM versions v1 + LEFT JOIN versions v2 ON v1.value = v2.value AND + v2.product_id = ? + WHERE v1.product_id = ? AND v2.value IS NULL", + undef, + $tgtprodid, $tgtprodid, $srcprodid); + +$dbh->do("INSERT INTO group_control_map (group_id, product_id, entry, membercontrol, othercontrol, canedit, editcomponents, editbugs, canconfirm) + SELECT g1.group_id, ?, g1.entry, g1.membercontrol, g1.othercontrol, g1.canedit, g1.editcomponents, g1.editbugs, g1.canconfirm + FROM group_control_map g1 + LEFT JOIN group_control_map g2 ON g1.product_id = ? AND + g2.product_id = ? AND + g1.group_id = g2.group_id + WHERE g1.product_id = ? AND g2.group_id IS NULL", + undef, + $tgtprodid, $srcprodid, $tgtprodid, $srcprodid); + +#$dbh->bz_commit_transaction(); + +exit(0); + diff --git a/contrib/sanitizeme.pl b/contrib/sanitizeme.pl new file mode 100644 index 000000000..362700be0 --- /dev/null +++ b/contrib/sanitizeme.pl @@ -0,0 +1,176 @@ +#!/usr/bin/perl -wT +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# The Initial Developer of the Original Code is the Mozilla +# Corporation. Portions created by Mozilla are +# Copyright (C) 2006 Mozilla Foundation. All Rights Reserved. +# +# Contributor(s): Myk Melez <myk@mozilla.org> +# Alex Brugh <alex@cs.umn.edu> +# Dave Miller <justdave@mozilla.com> +# Byron Jones <glob@mozilla.com> + +use strict; + +use lib qw(.); + +use Bugzilla; +use Bugzilla::Constants; +use Bugzilla::Util; + +use Getopt::Long; + +my $dbh = Bugzilla->dbh; + +# This SQL is designed to sanitize a copy of a Bugzilla database so that it +# doesn't contain any information that can't be viewed from a web browser by +# a user who is not logged in. + +# Last validated against Bugzilla version 4.0 + +my ($dry_run, $from_cron, $keep_attachments, $keep_groups, + $keep_passwords, $keep_insider, $trace) = (0, 0, 0, '', 0, 0, 0); +my $keep_groups_sql = ''; + +GetOptions( + "dry-run" => \$dry_run, + "from-cron" => \$from_cron, + "keep-attachments" => \$keep_attachments, + "keep-passwords" => \$keep_passwords, + "keep-insider" => \$keep_insider, + "keep-groups:s" => \$keep_groups, + "trace" => \$trace, +) or exit; + +if ($keep_groups ne '') { + my @groups; + foreach my $group_id (split(/\s*,\s*/, $keep_groups)) { + my $group; + if ($group_id =~ /\D/) { + $group = Bugzilla::Group->new({ name => $group_id }); + } else { + $group = Bugzilla::Group->new($group_id); + } + die "Invalid group '$group_id'\n" unless $group; + push @groups, $group->id; + } + $keep_groups_sql = "NOT IN (" . join(",", @groups) . ")"; +} + +$dbh->{TraceLevel} = 1 if $trace; + +if ($dry_run) { + print "** dry run : no changes to the database will be made **\n"; + $dbh->bz_start_transaction(); +} +eval { + delete_non_public_products(); + delete_secure_bugs(); + delete_insider_comments() unless $keep_insider; + delete_security_groups(); + delete_sensitive_user_data(); + delete_attachment_data() unless $keep_attachments; + print "All done!\n"; + $dbh->bz_rollback_transaction() if $dry_run; +}; +if ($@) { + $dbh->bz_rollback_transaction() if $dry_run; + die "$@" if $@; +} + +sub delete_non_public_products { + # Delete all non-public products, and all data associated with them + my @products = Bugzilla::Product->get_all(); + my $mandatory = CONTROLMAPMANDATORY; + foreach my $product (@products) { + # if there are any mandatory groups on the product, nuke it and + # everything associated with it (including the bugs) + Bugzilla->params->{'allowbugdeletion'} = 1; # override this in memory for now + my $mandatorygroups = $dbh->selectcol_arrayref("SELECT group_id FROM group_control_map WHERE product_id = ? AND (membercontrol = $mandatory)", undef, $product->id); + if (0 < scalar(@$mandatorygroups)) { + print "Deleting product '" . $product->name . "'...\n"; + $product->remove_from_db(); + } + } +} + +sub delete_secure_bugs { + # Delete all data for bugs in security groups. + my $buglist = $dbh->selectall_arrayref( + $keep_groups + ? "SELECT DISTINCT bug_id FROM bug_group_map WHERE group_id $keep_groups_sql" + : "SELECT DISTINCT bug_id FROM bug_group_map" + ); + $|=1; # disable buffering so the bug progress counter works + my $numbugs = scalar(@$buglist); + my $bugnum = 0; + print "Deleting $numbugs bugs in " . ($keep_groups ? 'non-' : '') . "security groups...\n"; + foreach my $row (@$buglist) { + my $bug_id = $row->[0]; + $bugnum++; + print "\r$bugnum/$numbugs" unless $from_cron; + my $bug = new Bugzilla::Bug($bug_id); + $bug->remove_from_db(); + } + print "\rDone \n" unless $from_cron; +} + +sub delete_insider_comments { + # Delete all 'insidergroup' comments and attachments + print "Deleting 'insidergroup' comments and attachments...\n"; + $dbh->do("DELETE FROM longdescs WHERE isprivate = 1"); + $dbh->do("DELETE attach_data FROM attachments JOIN attach_data ON attachments.attach_id = attach_data.id WHERE attachments.isprivate = 1"); + $dbh->do("DELETE FROM attachments WHERE isprivate = 1"); + $dbh->do("UPDATE bugs_fulltext SET comments = comments_noprivate"); +} + +sub delete_security_groups { + # Delete all security groups. + print "Deleting " . ($keep_groups ? 'non-' : '') . "security groups...\n"; + $dbh->do("DELETE user_group_map FROM groups JOIN user_group_map ON groups.id = user_group_map.group_id WHERE groups.isbuggroup = 1"); + $dbh->do("DELETE group_group_map FROM groups JOIN group_group_map ON (groups.id = group_group_map.member_id OR groups.id = group_group_map.grantor_id) WHERE groups.isbuggroup = 1"); + $dbh->do("DELETE group_control_map FROM groups JOIN group_control_map ON groups.id = group_control_map.group_id WHERE groups.isbuggroup = 1"); + $dbh->do("UPDATE flagtypes LEFT JOIN groups ON flagtypes.grant_group_id = groups.id SET grant_group_id = NULL WHERE groups.isbuggroup = 1"); + $dbh->do("UPDATE flagtypes LEFT JOIN groups ON flagtypes.request_group_id = groups.id SET request_group_id = NULL WHERE groups.isbuggroup = 1"); + if ($keep_groups) { + $dbh->do("DELETE FROM groups WHERE isbuggroup = 1 AND id $keep_groups_sql"); + } else { + $dbh->do("DELETE FROM groups WHERE isbuggroup = 1"); + } +} + +sub delete_sensitive_user_data { + # Remove sensitive user account data. + print "Deleting sensitive user account data...\n"; + $dbh->do("UPDATE profiles SET cryptpassword = 'deleted'") unless $keep_passwords; + $dbh->do("DELETE FROM profiles_activity"); + $dbh->do("DELETE FROM profile_search"); + $dbh->do("DELETE FROM namedqueries"); + $dbh->do("DELETE FROM tokens"); + $dbh->do("DELETE FROM logincookies"); + $dbh->do("DELETE FROM login_failure"); + $dbh->do("DELETE FROM ts_error"); + $dbh->do("DELETE FROM ts_exitstatus"); + $dbh->do("DELETE FROM ts_funcmap"); + $dbh->do("DELETE FROM ts_job"); + $dbh->do("DELETE FROM ts_note"); +} + +sub delete_attachment_data { + # Delete unnecessary attachment data. + print "Removing attachment data to preserve disk space...\n"; + $dbh->do("UPDATE attach_data SET thedata = ''"); +} + diff --git a/contrib/verify-user.pl b/contrib/verify-user.pl new file mode 100644 index 000000000..d12cd745f --- /dev/null +++ b/contrib/verify-user.pl @@ -0,0 +1,129 @@ +#!/usr/bin/perl -wT +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# The Initial Developer of the Original Code is Netscape Communications +# Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): Myk Melez <myk@mozilla.org> +# Dave Miller <justdave@bugzilla.org> + +# See if a user account has ever done anything + +# ./verify-user.pl foo@baz.com + +use strict; + +use lib qw(.); + +use Bugzilla; +use Bugzilla::Util; +use Bugzilla::DB; +use Bugzilla::Constants; + +# Make sure accounts were specified on the command line and exist. +my $user = $ARGV[0] || die "You must specify an user.\n"; +my $dbh = Bugzilla->dbh; +my $sth; + +#$sth = $dbh->prepare("SELECT name, count(*) as qty from bugs, products where reporter=198524 and product_id=products.id group by name order by qty desc"); +#$sth->execute(); +#my $results = $sth->fetchall_arrayref(); +#use Data::Dumper; +#print Data::Dumper::Dumper($results); +#exit; + +trick_taint($user); +if ($user =~ /^\d+$/) { # user ID passed instead of email + $sth = $dbh->prepare('SELECT login_name FROM profiles WHERE userid = ?'); + $sth->execute($user); + ($user) = $sth->fetchrow_array || die "The user with ID $ARGV[0] does not exist.\n"; + print "User $ARGV[0]'s login name is $user.\n"; +} +$sth = $dbh->prepare("SELECT userid FROM profiles WHERE login_name = ?"); +$sth->execute($user); +my ($user_id) = $sth->fetchrow_array || die "The user $user does not exist.\n"; + +print "${user}'s ID is $user_id.\n"; + +$sth = $dbh->prepare("SELECT DISTINCT ipaddr FROM logincookies WHERE userid = ?"); +$sth->execute($user_id); +my $iplist = $sth->fetchall_arrayref; +if (@$iplist > 0) { + print "This user has recently connected from the following IP addresses:\n"; + foreach my $ip (@$iplist) { + print $$ip[0] . "\n"; + } +} + + +# A list of tables and columns to be checked. +my $columns = { + attachments => ['submitter_id'] , + bugs => ['assigned_to', 'reporter', 'qa_contact'] , + bugs_activity => ['who'] , + cc => ['who'] , + components => ['initialowner', 'initialqacontact'] , + flags => ['setter_id', 'requestee_id'] , + logincookies => ['userid'] , + longdescs => ['who'] , + namedqueries => ['userid'] , + profiles_activity => ['userid', 'who'] , + quips => ['userid'] , + series => ['creator'] , + tokens => ['userid'] , + user_group_map => ['user_id'] , + votes => ['who'] , + watch => ['watcher', 'watched'] , + +}; + +my $fields = 0; +# Check records for user. +foreach my $table (keys(%$columns)) { + foreach my $column (@{$columns->{$table}}) { + $sth = $dbh->prepare("SELECT COUNT(*) FROM $table WHERE $column = ?"); + if ($table eq 'user_group_map') { + $sth = $dbh->prepare("SELECT COUNT(*) FROM $table WHERE $column = ? AND grant_type = " . GRANT_DIRECT); + } + $sth->execute($user_id); + my ($val) = $sth->fetchrow_array; + $fields++ if $val; + print "$table.$column: $val\n" if $val; + } +} + +print "The user is mentioned in $fields fields.\n"; + +if ($::ARGV[1] && $::ARGV[1] eq '-r') { + if ($fields == 0) { + $sth = $dbh->prepare("SELECT login_name FROM profiles WHERE login_name = ?"); + my $count = 0; + print "Finding an unused recycle ID"; + do { + $count++; + $sth->execute(sprintf("reuseme%03d\@bugzilla.org", $count)); + print "."; + } while (my ($match) = $sth->fetchrow_array()); + printf "\nUsing reuseme%03d\@bugzilla.org.\n", $count; + $dbh->do("DELETE FROM user_group_map WHERE user_id=?",undef,$user_id); + $dbh->do("UPDATE profiles SET realname='', cryptpassword='randomgarbage' WHERE userid=?",undef,$user_id); + $dbh->do("UPDATE profiles SET login_name=? WHERE userid=?",undef,sprintf("reuseme%03d\@bugzilla.org",$count),$user_id); + } + else { + print "Account has been used, so not recycling.\n"; + } +} diff --git a/enter_bug.cgi b/enter_bug.cgi index ffba2b09f..85e69e535 100755 --- a/enter_bug.cgi +++ b/enter_bug.cgi @@ -51,6 +51,7 @@ use Bugzilla::Keyword; use Bugzilla::Token; use Bugzilla::Field; use Bugzilla::Status; +use Bugzilla::UserAgent; my $user = Bugzilla->login(LOGIN_REQUIRED); @@ -62,9 +63,21 @@ my $dbh = Bugzilla->dbh; my $template = Bugzilla->template; my $vars = {}; +# BMO add a hook for the guided extension +Bugzilla::Hook::process('enter_bug_start', { vars => $vars }); + # All pages point to the same part of the documentation. $vars->{'doc_section'} = 'bugreports.html'; +if (!$vars->{'disable_guided'}) { + # Purpose: force guided format for newbies + $cgi->param(-name=>'format', -value=>'guided') + if !$cgi->param('format') && !$user->in_group('canconfirm'); + + $cgi->delete('format') + if ($cgi->param('format') && ($cgi->param('format') eq "__default__")); +} + my $product_name = trim($cgi->param('product') || ''); # Will contain the product object the bug is created in. my $product; @@ -74,8 +87,14 @@ if ($product_name eq '') { my @enterable_products = @{$user->get_enterable_products}; ThrowUserError('no_products') unless scalar(@enterable_products); - my $classification = Bugzilla->params->{'useclassification'} ? - scalar($cgi->param('classification')) : '__all'; + # MOZILLA CUSTOMIZATION + # skip the classification selection page + my $classification; + if (Bugzilla->params->{'useclassification'}) { + $classification = scalar($cgi->param('classification')) || '__all'; + } else { + $classification = '__all'; + } # Unless a real classification name is given, we sort products # by classification. @@ -166,195 +185,6 @@ sub formvalue { return Bugzilla->cgi->param($name) || $default || ""; } -# Takes the name of a field and a list of possible values for that -# field. Returns the first value in the list that is actually a -# valid value for that field. -# The field should be named after its DB table. -# Returns undef if none of the platforms match. -sub pick_valid_field_value (@) { - my ($field, @values) = @_; - my $dbh = Bugzilla->dbh; - - foreach my $value (@values) { - return $value if $dbh->selectrow_array( - "SELECT 1 FROM $field WHERE value = ?", undef, $value); - } - return undef; -} - -sub pickplatform { - return formvalue("rep_platform") if formvalue("rep_platform"); - - my @platform; - - if (Bugzilla->params->{'defaultplatform'}) { - @platform = Bugzilla->params->{'defaultplatform'}; - } else { - # If @platform is a list, this function will return the first - # item in the list that is a valid platform choice. If - # no choice is valid, we return "Other". - for ($ENV{'HTTP_USER_AGENT'}) { - #PowerPC - /\(.*PowerPC.*\)/i && do {push @platform, ("PowerPC", "Macintosh");}; - #AMD64, Intel x86_64 - /\(.*amd64.*\)/ && do {push @platform, ("AMD64", "x86_64", "PC");}; - /\(.*x86_64.*\)/ && do {push @platform, ("AMD64", "x86_64", "PC");}; - #Intel Itanium - /\(.*IA64.*\)/ && do {push @platform, "IA64";}; - #Intel x86 - /\(.*Intel.*\)/ && do {push @platform, ("IA32", "x86", "PC");}; - /\(.*[ix0-9]86.*\)/ && do {push @platform, ("IA32", "x86", "PC");}; - #Versions of Windows that only run on Intel x86 - /\(.*Win(?:dows |)[39M].*\)/ && do {push @platform, ("IA32", "x86", "PC");}; - /\(.*Win(?:dows |)16.*\)/ && do {push @platform, ("IA32", "x86", "PC");}; - #Sparc - /\(.*sparc.*\)/ && do {push @platform, ("Sparc", "Sun");}; - /\(.*sun4.*\)/ && do {push @platform, ("Sparc", "Sun");}; - #Alpha - /\(.*AXP.*\)/i && do {push @platform, ("Alpha", "DEC");}; - /\(.*[ _]Alpha.\D/i && do {push @platform, ("Alpha", "DEC");}; - /\(.*[ _]Alpha\)/i && do {push @platform, ("Alpha", "DEC");}; - #MIPS - /\(.*IRIX.*\)/i && do {push @platform, ("MIPS", "SGI");}; - /\(.*MIPS.*\)/i && do {push @platform, ("MIPS", "SGI");}; - #68k - /\(.*68K.*\)/ && do {push @platform, ("68k", "Macintosh");}; - /\(.*680[x0]0.*\)/ && do {push @platform, ("68k", "Macintosh");}; - #HP - /\(.*9000.*\)/ && do {push @platform, ("PA-RISC", "HP");}; - #ARM - /\(.*ARM.*\)/ && do {push @platform, ("ARM", "PocketPC");}; - #PocketPC intentionally before PowerPC - /\(.*Windows CE.*PPC.*\)/ && do {push @platform, ("ARM", "PocketPC");}; - #PowerPC - /\(.*PPC.*\)/ && do {push @platform, ("PowerPC", "Macintosh");}; - /\(.*AIX.*\)/ && do {push @platform, ("PowerPC", "Macintosh");}; - #Stereotypical and broken - /\(.*Windows CE.*\)/ && do {push @platform, ("ARM", "PocketPC");}; - /\(.*Macintosh.*\)/ && do {push @platform, ("68k", "Macintosh");}; - /\(.*Mac OS [89].*\)/ && do {push @platform, ("68k", "Macintosh");}; - /\(.*Win64.*\)/ && do {push @platform, "IA64";}; - /\(Win.*\)/ && do {push @platform, ("IA32", "x86", "PC");}; - /\(.*Win(?:dows[ -])NT.*\)/ && do {push @platform, ("IA32", "x86", "PC");}; - /\(.*OSF.*\)/ && do {push @platform, ("Alpha", "DEC");}; - /\(.*HP-?UX.*\)/i && do {push @platform, ("PA-RISC", "HP");}; - /\(.*IRIX.*\)/i && do {push @platform, ("MIPS", "SGI");}; - /\(.*(SunOS|Solaris).*\)/ && do {push @platform, ("Sparc", "Sun");}; - #Braindead old browsers who didn't follow convention: - /Amiga/ && do {push @platform, ("68k", "Macintosh");}; - /WinMosaic/ && do {push @platform, ("IA32", "x86", "PC");}; - } - } - - return pick_valid_field_value('rep_platform', @platform) || "Other"; -} - -sub pickos { - if (formvalue('op_sys') ne "") { - return formvalue('op_sys'); - } - - my @os = (); - - if (Bugzilla->params->{'defaultopsys'}) { - @os = Bugzilla->params->{'defaultopsys'}; - } else { - # This function will return the first - # item in @os that is a valid platform choice. If - # no choice is valid, we return "Other". - for ($ENV{'HTTP_USER_AGENT'}) { - /\(.*IRIX.*\)/ && do {push @os, "IRIX";}; - /\(.*OSF.*\)/ && do {push @os, "OSF/1";}; - /\(.*Linux.*\)/ && do {push @os, "Linux";}; - /\(.*Solaris.*\)/ && do {push @os, "Solaris";}; - /\(.*SunOS.*\)/ && do { - /\(.*SunOS 5.11.*\)/ && do {push @os, ("OpenSolaris", "Opensolaris", "Solaris 11");}; - /\(.*SunOS 5.10.*\)/ && do {push @os, "Solaris 10";}; - /\(.*SunOS 5.9.*\)/ && do {push @os, "Solaris 9";}; - /\(.*SunOS 5.8.*\)/ && do {push @os, "Solaris 8";}; - /\(.*SunOS 5.7.*\)/ && do {push @os, "Solaris 7";}; - /\(.*SunOS 5.6.*\)/ && do {push @os, "Solaris 6";}; - /\(.*SunOS 5.5.*\)/ && do {push @os, "Solaris 5";}; - /\(.*SunOS 5.*\)/ && do {push @os, "Solaris";}; - /\(.*SunOS.*sun4u.*\)/ && do {push @os, "Solaris";}; - /\(.*SunOS.*i86pc.*\)/ && do {push @os, "Solaris";}; - /\(.*SunOS.*\)/ && do {push @os, "SunOS";}; - }; - /\(.*HP-?UX.*\)/ && do {push @os, "HP-UX";}; - /\(.*BSD.*\)/ && do { - /\(.*BSD\/(?:OS|386).*\)/ && do {push @os, "BSDI";}; - /\(.*FreeBSD.*\)/ && do {push @os, "FreeBSD";}; - /\(.*OpenBSD.*\)/ && do {push @os, "OpenBSD";}; - /\(.*NetBSD.*\)/ && do {push @os, "NetBSD";}; - }; - /\(.*BeOS.*\)/ && do {push @os, "BeOS";}; - /\(.*AIX.*\)/ && do {push @os, "AIX";}; - /\(.*OS\/2.*\)/ && do {push @os, "OS/2";}; - /\(.*QNX.*\)/ && do {push @os, "Neutrino";}; - /\(.*VMS.*\)/ && do {push @os, "OpenVMS";}; - /\(.*Win.*\)/ && do { - /\(.*Windows XP.*\)/ && do {push @os, "Windows XP";}; - /\(.*Windows NT 6\.1.*\)/ && do {push @os, "Windows 7";}; - /\(.*Windows NT 6\.0.*\)/ && do {push @os, "Windows Vista";}; - /\(.*Windows NT 5\.2.*\)/ && do {push @os, "Windows Server 2003";}; - /\(.*Windows NT 5\.1.*\)/ && do {push @os, "Windows XP";}; - /\(.*Windows 2000.*\)/ && do {push @os, "Windows 2000";}; - /\(.*Windows NT 5.*\)/ && do {push @os, "Windows 2000";}; - /\(.*Win.*9[8x].*4\.9.*\)/ && do {push @os, "Windows ME";}; - /\(.*Win(?:dows |)M[Ee].*\)/ && do {push @os, "Windows ME";}; - /\(.*Win(?:dows |)98.*\)/ && do {push @os, "Windows 98";}; - /\(.*Win(?:dows |)95.*\)/ && do {push @os, "Windows 95";}; - /\(.*Win(?:dows |)16.*\)/ && do {push @os, "Windows 3.1";}; - /\(.*Win(?:dows[ -]|)NT.*\)/ && do {push @os, "Windows NT";}; - /\(.*Windows.*NT.*\)/ && do {push @os, "Windows NT";}; - }; - /\(.*Mac OS X.*\)/ && do { - /\(.*Mac OS X (?:|Mach-O |\()10.6.*\)/ && do {push @os, "Mac OS X 10.6";}; - /\(.*Mac OS X (?:|Mach-O |\()10.5.*\)/ && do {push @os, "Mac OS X 10.5";}; - /\(.*Mac OS X (?:|Mach-O |\()10.4.*\)/ && do {push @os, "Mac OS X 10.4";}; - /\(.*Mac OS X (?:|Mach-O |\()10.3.*\)/ && do {push @os, "Mac OS X 10.3";}; - /\(.*Mac OS X (?:|Mach-O |\()10.2.*\)/ && do {push @os, "Mac OS X 10.2";}; - /\(.*Mac OS X (?:|Mach-O |\()10.1.*\)/ && do {push @os, "Mac OS X 10.1";}; - # Unfortunately, OS X 10.4 was the first to support Intel. This is - # fallback support because some browsers refused to include the OS - # Version. - /\(.*Intel.*Mac OS X.*\)/ && do {push @os, "Mac OS X 10.4";}; - # OS X 10.3 is the most likely default version of PowerPC Macs - # OS X 10.0 is more for configurations which didn't setup 10.x versions - /\(.*Mac OS X.*\)/ && do {push @os, ("Mac OS X 10.3", "Mac OS X 10.0", "Mac OS X");}; - }; - /\(.*32bit.*\)/ && do {push @os, "Windows 95";}; - /\(.*16bit.*\)/ && do {push @os, "Windows 3.1";}; - /\(.*Mac OS \d.*\)/ && do { - /\(.*Mac OS 9.*\)/ && do {push @os, ("Mac System 9.x", "Mac System 9.0");}; - /\(.*Mac OS 8\.6.*\)/ && do {push @os, ("Mac System 8.6", "Mac System 8.5");}; - /\(.*Mac OS 8\.5.*\)/ && do {push @os, "Mac System 8.5";}; - /\(.*Mac OS 8\.1.*\)/ && do {push @os, ("Mac System 8.1", "Mac System 8.0");}; - /\(.*Mac OS 8\.0.*\)/ && do {push @os, "Mac System 8.0";}; - /\(.*Mac OS 8[^.].*\)/ && do {push @os, "Mac System 8.0";}; - /\(.*Mac OS 8.*\)/ && do {push @os, "Mac System 8.6";}; - }; - /\(.*Darwin.*\)/ && do {push @os, ("Mac OS X 10.0", "Mac OS X");}; - # Silly - /\(.*Mac.*\)/ && do { - /\(.*Mac.*PowerPC.*\)/ && do {push @os, "Mac System 9.x";}; - /\(.*Mac.*PPC.*\)/ && do {push @os, "Mac System 9.x";}; - /\(.*Mac.*68k.*\)/ && do {push @os, "Mac System 8.0";}; - }; - # Evil - /Amiga/i && do {push @os, "Other";}; - /WinMosaic/ && do {push @os, "Windows 95";}; - /\(.*PowerPC.*\)/ && do {push @os, "Mac System 9.x";}; - /\(.*PPC.*\)/ && do {push @os, "Mac System 9.x";}; - /\(.*68K.*\)/ && do {push @os, "Mac System 8.0";}; - } - } - - push(@os, "Windows") if grep(/^Windows /, @os); - push(@os, "Mac OS") if grep(/^Mac /, @os); - - return pick_valid_field_value('op_sys', @os) || "Other"; -} ############################################################################## # End of subroutines ############################################################################## @@ -469,8 +299,8 @@ else { $default{'component_'} = formvalue('component'); $default{'priority'} = formvalue('priority', Bugzilla->params->{'defaultpriority'}); $default{'bug_severity'} = formvalue('bug_severity', Bugzilla->params->{'defaultseverity'}); - $default{'rep_platform'} = pickplatform(); - $default{'op_sys'} = pickos(); + $default{'rep_platform'} = detect_platform(); + $default{'op_sys'} = detect_op_sys(); $vars->{'alias'} = formvalue('alias'); $vars->{'short_desc'} = formvalue('short_desc'); diff --git a/extensions/BMO/Extension.pm b/extensions/BMO/Extension.pm index 79edaad3e..c800ade3d 100644 --- a/extensions/BMO/Extension.pm +++ b/extensions/BMO/Extension.pm @@ -42,6 +42,7 @@ use DateTime; use Bugzilla::Extension::BMO::FakeBug; use Bugzilla::Extension::BMO::Data qw($cf_visible_in_products $cf_flags + $cf_disabled_flags %group_to_cc_map $blocking_trusted_setters $blocking_trusted_requesters @@ -51,7 +52,8 @@ use Bugzilla::Extension::BMO::Data qw($cf_visible_in_products %always_fileable_group %product_sec_groups); use Bugzilla::Extension::BMO::Reports qw(user_activity_report - triage_reports); + triage_reports + group_admins); our $VERSION = '0.1'; @@ -69,6 +71,7 @@ sub template_before_process { my $vars = $args->{'vars'}; $vars->{'cf_hidden_in_product'} = \&cf_hidden_in_product; + $vars->{'cf_flag_disabled'} = \&cf_flag_disabled; if ($file =~ /^list\/list/) { # Purpose: enable correct sorting of list table @@ -155,8 +158,8 @@ sub page_before_template { # that our hook template can see. Bugzilla->request_cache->{'bmo_fields_page'} = 1; } - elsif ($page eq 'remo-form-payment.html') { - _remo_form_payment($vars); + elsif ($page eq 'group_admins.html') { + group_admins($vars); } } @@ -242,6 +245,13 @@ sub cf_hidden_in_product { return 0; } +sub cf_flag_disabled { + my ($field_name, $bug) = @_; + return 0 unless grep { $field_name eq $_ } @$cf_disabled_flags; + my $value = $bug->{$field_name}; + return $value eq '---' || $value eq ''; +} + # Purpose: CC certain email addresses on bugmail when a bug is added or # removed from a particular group. sub bugmail_recipients { @@ -440,6 +450,19 @@ sub _link_hg { return qq{<a href="https://hg.mozilla.org/$repo/rev/$id">$text</a>}; } +sub _link_bzr { + my $args = shift; + my $preamble = html_quote($args->{matches}->[0]); + my $url = html_quote($args->{matches}->[1]); + my $text = html_quote($args->{matches}->[2]); + my $id = html_quote($args->{matches}->[3]); + + $url =~ s/\s+$//; + $url =~ s/\/$//; + + return qq{$preamble<a href="http://$url/revision/$id">$text</a>}; +} + sub bug_format_comment { my ($self, $args) = @_; my $regexes = $args->{'regexes'}; @@ -466,6 +489,13 @@ sub bug_format_comment { replace => \&_link_svn }); + push (@$regexes, { + match => qr/\b(Committing\sto:\sbzr\+ssh:\/\/ + (?:[^\@]+\@)?(bzr\.mozilla\.org[^\n]+)\n.*?\nCommitted\s) + (revision\s(\d+))\./sx, + replace => \&_link_bzr + }); + # Note: for grouping in this regexp, always use non-capturing parentheses. my $hgrepos = join('|', qw!(?:releases/)?comm-[\w.]+ (?:releases/)?mozilla-[\w.]+ @@ -597,146 +627,6 @@ sub install_update_db { } } -sub _remo_form_payment { - my ($vars) = @_; - my $input = Bugzilla->input_params; - - my $user = Bugzilla->login(LOGIN_REQUIRED); - - if ($input->{'action'} eq 'commit') { - my $template = Bugzilla->template; - my $cgi = Bugzilla->cgi; - my $dbh = Bugzilla->dbh; - - my $bug_id = $input->{'bug_id'}; - detaint_natural($bug_id); - my $bug = Bugzilla::Bug->check($bug_id); - - # Detect if the user already used the same form to submit again - my $token = trim($input->{'token'}); - if ($token) { - my ($creator_id, $date, $old_attach_id) = Bugzilla::Token::GetTokenData($token); - if (!$creator_id - || $creator_id != $user->id - || $old_attach_id !~ "^remo_form_payment:") - { - # The token is invalid. - ThrowUserError('token_does_not_exist'); - } - - $old_attach_id =~ s/^remo_form_payment://; - if ($old_attach_id) { - ThrowUserError('remo_payment_cancel_dupe', - { bugid => $bug_id, attachid => $old_attach_id }); - } - } - - # Make sure the user can attach to this bug - if (!$bug->user->{'canedit'}) { - ThrowUserError("remo_payment_bug_edit_denied", - { bug_id => $bug->id }); - } - - # Make sure the bug is under the correct product/component - if ($bug->product ne 'Mozilla Reps' - || $bug->component ne 'Budget Requests') - { - ThrowUserError('remo_payment_invalid_product'); - } - - my ($timestamp) = $dbh->selectrow_array("SELECT NOW()"); - - $dbh->bz_start_transaction; - - # Create the comment to be added based on the form fields from rep-payment-form - my $comment; - $template->process("pages/comment-remo-form-payment.txt.tmpl", $vars, \$comment) - || ThrowTemplateError($template->error()); - $bug->add_comment($comment, { isprivate => 0 }); - - # Attach expense report - # FIXME: Would be nice to be able to have the above prefilled comment and - # the following attachments all show up under a single comment. But the longdescs - # table can only handle one attach_id per comment currently. At least only one - # email is sent the way it is done below. - my $attachment; - if (defined $cgi->upload('expenseform')) { - # Determine content-type - my $content_type = $cgi->uploadInfo($cgi->param('expenseform'))->{'Content-Type'}; - - $attachment = Bugzilla::Attachment->create( - { bug => $bug, - creation_ts => $timestamp, - data => $cgi->upload('expenseform'), - description => 'Expense Form', - filename => scalar $cgi->upload('expenseform'), - ispatch => 0, - isprivate => 0, - isurl => 0, - mimetype => $content_type, - store_in_file => 0, - }); - - # Insert comment for attachment - $bug->add_comment('', { isprivate => 0, - type => CMT_ATTACHMENT_CREATED, - extra_data => $attachment->id }); - } - - # Attach receipts file - if (defined $cgi->upload("receipts")) { - # Determine content-type - my $content_type = $cgi->uploadInfo($cgi->param("receipts"))->{'Content-Type'}; - - $attachment = Bugzilla::Attachment->create( - { bug => $bug, - creation_ts => $timestamp, - data => $cgi->upload('receipts'), - description => "Receipts", - filename => scalar $cgi->upload("receipts"), - ispatch => 0, - isprivate => 0, - isurl => 0, - mimetype => $content_type, - store_in_file => 0, - }); - - # Insert comment for attachment - $bug->add_comment('', { isprivate => 0, - type => CMT_ATTACHMENT_CREATED, - extra_data => $attachment->id }); - } - - $bug->update($timestamp); - - if ($token) { - trick_taint($token); - $dbh->do('UPDATE tokens SET eventdata = ? WHERE token = ?', undef, - ("remo_form_payment:" . $attachment->id, $token)); - } - - $dbh->bz_commit_transaction; - - # Define the variables and functions that will be passed to the UI template. - $vars->{'attachment'} = $attachment; - $vars->{'bugs'} = [ new Bugzilla::Bug($bug_id) ]; - $vars->{'header_done'} = 1; - $vars->{'contenttypemethod'} = 'autodetect'; - - my $recipients = { 'changer' => $user }; - $vars->{'sent_bugmail'} = Bugzilla::BugMail::Send($bug_id, $recipients); - - print $cgi->header(); - # Generate and return the UI (HTML page) from the appropriate template. - $template->process("attachment/created.html.tmpl", $vars) - || ThrowTemplateError($template->error()); - exit; - } - else { - $vars->{'token'} = issue_session_token('remo_form_payment:'); - } -} - sub _last_closed_date { my ($self) = @_; my $dbh = Bugzilla->dbh; @@ -796,4 +686,61 @@ sub webservice { $dispatch->{BMO} = "Bugzilla::Extension::BMO::WebService"; } +our $search_content_matches; +BEGIN { + $search_content_matches = \&Bugzilla::Search::_content_matches; +} + +sub search_operator_field_override { + my ($self, $args) = @_; + my $search = $args->{'search'}; + my $operators = $args->{'operators'}; + + my $cgi = Bugzilla->cgi; + my @comments = $cgi->param('comments'); + my $exclude_comments = scalar(@comments) && !grep { $_ eq '1' } @comments; + + if ($cgi->param('query_format') 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 + + my $self = shift; + my %func_args = @_; + my ($chartid, $supptables, $term, $groupby, $fields, $t, $v) = + @func_args{qw(chartid supptables term groupby fields t v)}; + my $dbh = Bugzilla->dbh; + + # Add the fulltext table to the query so we can search on it. + my $table = "bugs_fulltext_$$chartid"; + push(@$supptables, "LEFT JOIN bugs_fulltext AS $table " . + "ON bugs.bug_id = $table.bug_id"); + + # Create search terms to add to the SELECT and WHERE clauses. + my ($term1, $rterm1) = $dbh->sql_fulltext_search("$table.short_desc", $$v, 1); + $rterm1 = $term1 if !$rterm1; + + # The term to use in the WHERE clause. + $$term = $term1; + if ($$t =~ /not/i) { + $$term = "NOT($$term)"; + } + + my $current = Bugzilla::Search::COLUMNS->{'relevance'}->{name}; + $current = $current ? "$current + " : ''; + # For NOT searches, we just add 0 to the relevance. + my $select_term = $$t =~ /not/ ? 0 : "($current$rterm1)"; + Bugzilla::Search::COLUMNS->{'relevance'}->{name} = $select_term; +} + __PACKAGE__->NAME; diff --git a/extensions/BMO/lib/Data.pm b/extensions/BMO/lib/Data.pm index 17b84a37e..ccc729a6d 100644 --- a/extensions/BMO/lib/Data.pm +++ b/extensions/BMO/lib/Data.pm @@ -27,7 +27,7 @@ use base qw(Exporter); use Tie::IxHash; our @EXPORT_OK = qw($cf_visible_in_products - $cf_flags + $cf_flags $cf_disabled_flags %group_to_cc_map $blocking_trusted_setters $blocking_trusted_requesters @@ -78,7 +78,6 @@ tie(%$cf_visible_in_products, "Tie::IxHash", "Add-on SDK" => [], "addons.mozilla.org" => [], "AUS" => [], - "Camino" => [], "Core Graveyard" => [], "Core" => [], "Directory" => [], @@ -108,6 +107,9 @@ tie(%$cf_visible_in_products, "Tie::IxHash", "Server Operations: Security", ], }, + qw/^cf_office$/ => { + "mozilla.org" => ["Server Operations: Desktop Issues"], + }, qr/^cf_crash_signature$/ => { "addons.mozilla.org" => [], "Add-on SDK" => [], @@ -136,6 +138,9 @@ tie(%$cf_visible_in_products, "Tie::IxHash", "Mozilla Labs" => [], "mozilla.org" => [], "Tech Evangelism" => [], + }, + qw/^cf_due_date$/ => { + "Mozilla Reps" => [], }, ); @@ -144,6 +149,28 @@ our $cf_flags = [ qr/^cf_(?:blocking|tracking|status)_/, ]; +# List of disabled fields. +# Temp kludge until custom fields can be disabled correctly upstream. +# Disabled fields are hidden unless they have a value set +our $cf_disabled_flags = [ + 'cf_blocking_20', + 'cf_status_20', + 'cf_tracking_firefox5', + 'cf_status_firefox5', + 'cf_blocking_thunderbird32', + 'cf_status_thunderbird32', + 'cf_blocking_thunderbird30', + 'cf_status_thunderbird30', + 'cf_blocking_seamonkey21', + 'cf_status_seamonkey21', + 'cf_tracking_seamonkey22', + 'cf_status_seamonkey22', + 'cf_tracking_firefox6', + 'cf_status_firefox6', + 'cf_tracking_thunderbird6', + 'cf_status_thunderbird6', +]; + # Who to CC on particular bugmails when certain groups are added or removed. our %group_to_cc_map = ( 'bugzilla-security' => 'security@bugzilla.org', diff --git a/extensions/BMO/lib/FakeBug.pm b/extensions/BMO/lib/FakeBug.pm index d8cebe379..5610f5433 100644 --- a/extensions/BMO/lib/FakeBug.pm +++ b/extensions/BMO/lib/FakeBug.pm @@ -1,7 +1,5 @@ package Bugzilla::Extension::BMO::FakeBug; -use strict; - # 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 diff --git a/extensions/BMO/lib/Reports.pm b/extensions/BMO/lib/Reports.pm index d1f979beb..f291e72e7 100644 --- a/extensions/BMO/lib/Reports.pm +++ b/extensions/BMO/lib/Reports.pm @@ -31,7 +31,8 @@ use DateTime; use base qw(Exporter); our @EXPORT_OK = qw(user_activity_report - triage_reports); + triage_reports + group_admins); sub user_activity_report { my ($vars) = @_; @@ -303,14 +304,16 @@ sub triage_reports { # load product and components from input - my $product = Bugzilla::Product->new({ name => $input->{'product'} }); + 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 }); + my $component = Bugzilla::Component->new({ name => $component_name, product => $product }) + || ThrowUserError('invalid_object', { object => 'Component', value => $component_name }); push @component_ids, $component->id; } } @@ -319,15 +322,22 @@ sub triage_reports { 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'} }); + my $user = Bugzilla::User->new({ name => $input->{'commenter_is'} }) + || ThrowUserError('invalid_object', { object => 'User', value => $input->{'commenter_is'} }); $filter_commenter_id = $user ? $user->id : 0; } - my $filter_last = $input->{'filter_last'}; - my $filter_last_period = $input->{'last'}; my $filter_last_time; if ($filter_last) { if ($filter_last_period eq 'is') { @@ -338,11 +348,10 @@ sub triage_reports { $filter_last_period = 14 if $filter_last_period < 14; } } - my $now = (time); - $filter_commenter = 1 unless $filter_commenter || $filter_last; # form sql queries + my $now = (time); my $bugs_sql = " SELECT bug_id, short_desc, reporter, creation_ts FROM bugs @@ -473,4 +482,41 @@ sub triage_reports { $vars->{'input'} = $input; } +sub group_admins { + my ($vars, $filter) = @_; + my $dbh = Bugzilla->dbh; + my $user = Bugzilla->user; + + $user->in_group('editusers') + || ThrowUserError('auth_failure', { group => 'editusers', + action => 'run', + object => 'group_admins' }); + + my $query = " + SELECT groups.name, " . + $dbh->sql_group_concat('profiles.login_name', "','", 1) . " + FROM groups + LEFT JOIN user_group_map + ON user_group_map.group_id = groups.id + AND user_group_map.isbless = 1 + AND user_group_map.grant_type = 0 + LEFT JOIN profiles + ON user_group_map.user_id = profiles.userid + WHERE groups.isbuggroup = 1 + GROUP BY groups.name"; + + my @groups; + foreach my $group (@{ $dbh->selectall_arrayref($query) }) { + my @admins; + if ($group->[1]) { + foreach my $admin (split(/,/, $group->[1])) { + push(@admins, Bugzilla::User->new({ name => $admin })); + } + } + push(@groups, { name => $group->[0], admins => \@admins }); + } + + $vars->{'groups'} = \@groups; +} + 1; diff --git a/extensions/BMO/template/en/default/account/create.html.tmpl b/extensions/BMO/template/en/default/account/create.html.tmpl index 275df01f8..47355cf00 100644 --- a/extensions/BMO/template/en/default/account/create.html.tmpl +++ b/extensions/BMO/template/en/default/account/create.html.tmpl @@ -122,17 +122,17 @@ function onSubmit() { <ol> <li> Please consider reading our - <a href="https://developer.mozilla.org/en/Bug_writing_guidelines" target="_blank">[% terms.bug %] writing guidelines</a>. + <a href="https://developer.mozilla.org/en/Bug_writing_guidelines" target="_blank">bug writing guidelines</a>. </li> <li> - [% terms.Bugzilla %] is a public place, so what you type and your email address will be visible + Bugzilla is a public place, so what you type and your email address will be visible to all logged-in users. Some people use an <a href="http://email.about.com/od/freeemailreviews/tp/free_email.htm" target="_blank">alternative email address</a> for this reason. </li> <li> Please give us an email address you want to use. Once we confirm that it works, - you'll be asked to set a password and then you can start filing [% terms.bugs %] and helping fix them. + you'll be asked to set a password and then you can start filing bugs and helping fix them. </li> </ol> </div> @@ -158,9 +158,9 @@ function onSubmit() { </table> <p id="bmo-admin"> - If you think there's something wrong with [% terms.Bugzilla %], you can + If you think there's something wrong with Bugzilla, you can <a href="mailto:bugzilla-admin@mozilla.org">send an email to the admins</a>, but - remember, they can't file [% terms.bugs %] for you, or solve tech support problems. + remember, they can't file bugs for you, or solve tech support problems. </p> [% PROCESS global/footer.html.tmpl %] diff --git a/extensions/BMO/template/en/default/bug/create/create-brownbag.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-brownbag.html.tmpl index 72d520dd4..e4c6cabfb 100644 --- a/extensions/BMO/template/en/default/bug/create/create-brownbag.html.tmpl +++ b/extensions/BMO/template/en/default/bug/create/create-brownbag.html.tmpl @@ -80,17 +80,16 @@ function trySubmit() { <form method="post" action="post_bug.cgi" id="brownbagRequestForm" enctype="multipart/form-data" onSubmit="return trySubmit();"> - <input type="hidden" name="product" value="mozilla.org"> - <input type="hidden" name="component" value="Server Operations: Desktop Issues"> - <input type="hidden" name="rep_platform" value="All"> - <input type="hidden" name="op_sys" value="Other"> - <input type="hidden" name="priority" value="--"> - <input type="hidden" name="version" value="other"> - <input type="hidden" name="bug_severity" id="bug_severity" value="normal"> - <input type="hidden" name="comment" id="comment" value=""> - <input type="hidden" name="short_desc" id="short_desc" value=""> - <input type="hidden" name="groups" value="mozilla-corporation-confidential"> - + <input type="hidden" name="product" value="mozilla.org"> + <input type="hidden" name="component" value="Server Operations: Desktop Issues"> + <input type="hidden" name="rep_platform" value="All"> + <input type="hidden" name="op_sys" value="Other"> + <input type="hidden" name="priority" value="--"> + <input type="hidden" name="version" value="other"> + <input type="hidden" name="bug_severity" id="bug_severity" value="normal"> + <input type="hidden" name="comment" id="comment" value=""> + <input type="hidden" name="short_desc" id="short_desc" value=""> + <input type="hidden" name="groups" value="mozilla-corporation-confidential"> <table> <tr> @@ -98,6 +97,7 @@ function trySubmit() { <td> <input type="text" name="presenter" id="presenter" value="" size="60" /> </td> + </tr> <tr> @@ -146,7 +146,7 @@ function trySubmit() { <option value="AM" selected>AM</option> <option value="PM">PM</option> </select> - </td> + </td> </tr> <tr> @@ -171,14 +171,14 @@ function trySubmit() { </tr> <tr> - <td align="right"><strong>Archive this?</strong></td> - <td align="left"><input type="checkbox" name="archive" id="archive" value="yes"></td> +<td align="right"><strong>Archive this?</strong></td> +<td align="left"><input type="checkbox" name="archive" id="archive" value="yes"></td> </tr> <tr> - <td align="right"><strong>Need IT to help run A/V?</strong></td> - <td align="left"><input type="checkbox" name="ithelp" id="ithelp" value="yes" checked></td> +<td align="right"><strong>Need IT to help run A/V?</strong></td> +<td align="left"><input type="checkbox" name="ithelp" id="ithelp" value="yes" checked></td> </tr> <tr> @@ -198,11 +198,12 @@ function trySubmit() { <th><label for="description">Description</label>:</th> <td> <em>Please briefly describe the brownbag and any specific needs you might have.</em><br> + <textarea id="description" name="description" rows="10" cols="80"></textarea> </td> </tr> -</table> + </table> <br> <input type="submit" id="commit" value="Submit Request"> diff --git a/extensions/BMO/template/en/default/bug/create/create-itrequest.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-itrequest.html.tmpl index d2f30475d..08207fd8c 100644 --- a/extensions/BMO/template/en/default/bug/create/create-itrequest.html.tmpl +++ b/extensions/BMO/template/en/default/bug/create/create-itrequest.html.tmpl @@ -32,7 +32,7 @@ [% USE Bugzilla %] <p><strong>Please use this form for IT requests only!</strong></p> -<p>If you have a [% terms.bug %] to file, go <a href="enter_bug.cgi">here</a>.</p> +<p>If you have a bug to file, go <a href="enter_bug.cgi">here</a>.</p> <form method="post" action="post_bug.cgi" id="itRequestForm" enctype="multipart/form-data"> <input type="hidden" name="product" value="mozilla.org"> @@ -75,12 +75,12 @@ <td> <select id="bug_severity" name="bug_severity" onchange="setsevdesc(this)"> - <option value="blocker">All work stops until this is done</option> - <option value="critical">As soon as possible (urgent)</option> - <option value="major">Within 24 hours</option> - <option value="normal">Within the next week</option> - <option value="minor" selected="selected">No rush</option> - <option value="trivial">Whenever you get around to it</option> + <option value="blocker">All work for IT stops until this is done</option> + <option value="critical">IT should work on it soon as possible (urgent)</option> + <option value="major">IT should get to it within 24 hours</option> + <option value="normal">IT should get to it within the next week</option> + <option value="minor" selected="selected">No rush, but hopefully IT can get to it soon</option> + <option value="trivial">Whenever IT can get around to it</option> <option value="enhancement">This is just an idea, filing it so we don't forget</option> </select> </td> @@ -96,13 +96,16 @@ <input type="radio" name="component" id="componentac" onclick="setcompdesc(this)" value="Server Operations: Account Requests"> <label for="componentac">Request an LDAP/E-mail/etc. account</label><br> <input type="radio" name="component" id="componentmvd" onclick="setcompdesc(this)" value="Server Operations: Desktop Issues"> - <label for="componentmvd">Desktop/Laptop/Printer/Phone problem/order/request</label><br> - <input type="radio" name="component" id="componenttbm" onclick="setcompdesc(this)" value="Server Operations: Tinderbox Maintenance"> + <label for="componentmvd">Desktop/Laptop/Printer/Phone/Tablet/License problem/order/request</label><br> + <input type="radio" name="component" id="componenttbm" onclick="setcompdesc(this)" value="Server Operations: RelEng"> <label for="componenttbm">Report a problem with a tinderbox machine</label><br> - <input type="radio" name="component" id="componentwcp" onclick="setcompdesc(this)" value="Server Operations: Web Content Push"> - <label for="componentwcp">Deploy a change to a production website</label><br> + <input type="radio" name="component" id="componentwcp" onclick="setcompdesc(this)" value="Server Operations: Web Operations"> + <label for="componentwcp">Report a problem with a Mozilla website, or to request a change or push</label><br> + <input type="radio" name="component" id="componentacl" onclick="setcompdesc(this)" value="Server Operations: ACL Request"> + <label for="componentacl">Request a firewall change</label><br> <input type="radio" name="component" id="componentso" onclick="setcompdesc(this)" value="Server Operations"> <label for="componentso">Any other issue</label><br> + Mailing list requests should be filed <a href="[% ulrbase FILTER none %]enter_bug.cgi?product=mozilla.org&format=mozlist">here</a> instead. </td> <td id="compdescription" align="left" style="color: green; padding-left: 1em"> </td> @@ -169,7 +172,7 @@ </table> <br> - <!-- infra [% terms.bugs %] --> + <!-- infra bugs --> <input type="checkbox" name="groups" id="groups" value="infra" checked="checked"><label for="groups"><strong>This is an internal issue which should not be publicly visible.</strong></label><br>(please uncheck this box if it isn't) <br><br> diff --git a/extensions/BMO/template/en/default/bug/create/create-mktgevent.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-mktgevent.html.tmpl index 92354eac3..d6b6c188f 100644 --- a/extensions/BMO/template/en/default/bug/create/create-mktgevent.html.tmpl +++ b/extensions/BMO/template/en/default/bug/create/create-mktgevent.html.tmpl @@ -91,18 +91,19 @@ function validateAndSubmit() { <form method="post" action="post_bug.cgi" id="swagRequestForm" enctype="multipart/form-data" onSubmit="return validateAndSubmit();"> - <input type="hidden" name="format" value="mktgevent"> - <input type="hidden" name="product" value="Marketing"> - <input type="hidden" name="component" value="Event Requests"> - <input type="hidden" name="rep_platform" value="All"> - <input type="hidden" name="op_sys" value="Other"> - <input type="hidden" name="priority" value="--"> - <input type="hidden" name="version" value="unspecified"> - <input type="hidden" name="bug_severity" id="bug_severity" value="normal"> - <input type="hidden" name="short_desc" id="short_desc" value=""> - <input type="hidden" name="groups" value="mozilla-corporation-confidential"> - + <input type="hidden" name="format" value="mktgevent"> + <input type="hidden" name="product" value="Marketing"> + <input type="hidden" name="component" value="Event Requests"> + <input type="hidden" name="rep_platform" value="All"> + <input type="hidden" name="op_sys" value="Other"> + <input type="hidden" name="priority" value="--"> + <input type="hidden" name="version" value="unspecified"> + <input type="hidden" name="bug_severity" id="bug_severity" value="normal"> + + <input type="hidden" name="short_desc" id="short_desc" value=""> + <input type="hidden" name="groups" value="mozilla-corporation-confidential"> <table> + <tr> <td align="right"><strong>First Name: <span style="color: red;">*</span></strong></td> <td align="left"> diff --git a/extensions/BMO/template/en/default/bug/create/create-mozlist.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-mozlist.html.tmpl index 0a2edb5ee..138f1754b 100644 --- a/extensions/BMO/template/en/default/bug/create/create-mozlist.html.tmpl +++ b/extensions/BMO/template/en/default/bug/create/create-mozlist.html.tmpl @@ -88,21 +88,21 @@ var listName = document.getElementById('listName').value; var listAdmin = document.getElementById('listAdmin').value; var listTypeRadio = document.getElementsByName('listType'); - var listType = ""; + var listType = ""; - for (var i = 0; i < listTypeRadio.length; i++) { - if (listTypeRadio[i].checked) { - listType = listTypeRadio[i].value; - } - } + for (var i = 0; i < listTypeRadio.length; i++) { + if (listTypeRadio[i].checked) { + listType = listTypeRadio[i].value; + } + } var alert_text = ""; var short_desc = ""; - if (listType) { + if (listType) { if (listType == "lists.mozilla.org") { document.getElementById('component').value = "Discussion Forums"; - short_desc = "Discussion Forum: " + listName; + short_desc = "Discussion Forum: " + listName; } else if (listType == "mozilla.com" ) { document.getElementById('component').value = "Server Operations: Desktop Issues"; short_desc = "[Zimbra Distribution List Request] " + listName + "@" + listType; @@ -112,7 +112,7 @@ } } else { alert_text += "Please select a list type\n"; - } + } if (!isFilledOut('listName')) { alert_text += "Please enter the list name\n"; @@ -127,7 +127,7 @@ return false; } - document.getElementById('short_desc').value = short_desc; + document.getElementById('short_desc').value = short_desc; return true; } @@ -220,8 +220,8 @@ <br> <b>Note:</b>The list administrator is also initially considered to be the list moderator and will be responsible for moderation tasks unless delegated to someone else. For - convenience, [% terms.Bugzilla %] user accounts will autocomplete. The administrator is not required - to have a [% terms.Bugzilla %] account, and you can enter an address that doesn't autocomplete if + convenience, Bugzilla user accounts will autocomplete. The administrator is not required + to have a Bugzilla account, and you can enter an address that doesn't autocomplete if necessary.<hr /> </td> </tr> @@ -287,7 +287,7 @@ <br> <div id="groups" style="display:none;"> - <!-- infra [% terms.bugs %] --> + <!-- infra bugs --> <input type="checkbox" name="groups" id="group_35" value="infra" disabled="true"> <label for="group_35"><strong>This is an internal issue which should not be publicly visible.</strong></label> <br><br> diff --git a/extensions/BMO/template/en/default/bug/create/create-mozpr.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-mozpr.html.tmpl index 5b4cbf999..28a37a31e 100644 --- a/extensions/BMO/template/en/default/bug/create/create-mozpr.html.tmpl +++ b/extensions/BMO/template/en/default/bug/create/create-mozpr.html.tmpl @@ -57,12 +57,10 @@ var flags = new Array([% product.components.size %]); comp_desc[[% count %]] = "[% c.description FILTER html_light FILTER js %]"; initialowners[[% count %]] = "[% c.default_assignee.login FILTER js %]"; [% flag_list = [] %] - [% FOREACH f = c.flag_types.bug %] - [% NEXT UNLESS f.is_active %] + [% FOREACH f = c.flag_types(is_active=>1).bug %] [% flag_list.push(f.id) %] [% END %] - [% FOREACH f = c.flag_types.attachment %] - [% NEXT UNLESS f.is_active %] + [% FOREACH f = c.flag_types(is_active=>1).attachment %] [% flag_list.push(f.id) %] [% END %] flags[[% count %]] = [[% flag_list.join(",") FILTER js %]]; @@ -301,9 +299,9 @@ TUI_hide_default('expert_fields'); </td> </tr> </table> - <input type="hidden" name="bug_severity" value="[% default.bug_severity FILTER html %]"> - <input type="hidden" name="rep_platform" value="[% default.rep_platform FILTER html %]"> - <input type="hidden" name="op_sys" value="[% default.op_sys FILTER html %]"> + <input type="hidden" name="bug_severity" value="[% default.bug_severity %]"> + <input type="hidden" name="rep_platform" value="[% default.rep_platform %]"> + <input type="hidden" name="op_sys" value="[% default.op_sys %]"> <input type="hidden" name="version" value="unspecified"> </td> </tr> @@ -335,18 +333,17 @@ TUI_hide_default('expert_fields'); %] <td rowspan="[% num_rows FILTER html %]"> - [% IF product.flag_types.bug.size > 0 %] + [% IF product.flag_types(is_active=>1).bug.size > 0 %] [% display_flag_headers = 0 %] [% any_flags_requesteeble = 0 %] - [% FOREACH flag_type = product.flag_types.bug %] - [% NEXT UNLESS flag_type.is_active %] + [% FOREACH flag_type = product.flag_types(is_active=>1).bug %] [% display_flag_headers = 1 %] [% SET any_flags_requesteeble = 1 IF flag_type.is_requestable && flag_type.is_requesteeble %] [% END %] [% IF display_flag_headers %] - [% PROCESS "flag/list.html.tmpl" flag_types = product.flag_types.bug + [% PROCESS "flag/list.html.tmpl" flag_types = product.flag_types(is_active=>1).bug any_flags_requesteeble = any_flags_requesteeble flag_table_id = "bug_flags" %] @@ -469,7 +466,7 @@ TUI_hide_default('expert_fields'); <td colspan="3"> [% defaultcontent = BLOCK %] [% IF cloned_bug_id %] -+++ This [% terms.bug %] was initially created as a clone of [% terms.Bug %] #[% cloned_bug_id FILTER html %] +++ ++++ This [% terms.bug %] was initially created as a clone of [% terms.Bug %] #[% cloned_bug_id %] +++ [% END %] @@ -526,7 +523,7 @@ TUI_hide_default('expert_fields'); <legend>Add an attachment</legend> <table class="attachment_entry"> [% PROCESS attachment/createformcontents.html.tmpl - flag_types = product.flag_types.attachment + flag_types = product.flag_types(is_active=>1).attachment any_flags_requesteeble = 1 flag_table_id ="attachment_flags" %] </table> @@ -555,7 +552,7 @@ TUI_hide_default('expert_fields'); <th>Status Whiteboard:</th> <td colspan="3"> <input id="status_whiteboard" name="status_whiteboard" size="70" - value="[% status_whiteboard FILTER html %]"> + value="[% status_whiteboard %]"> </td> </tr> <tr> @@ -592,10 +589,10 @@ TUI_hide_default('expert_fields'); <!-- Checkboxes --> [% FOREACH g = group %] - <input type="checkbox" id="bit-[% g.bit FILTER html %]" - name="bit-[% g.bit FILTER html %]" value="1" + <input type="checkbox" id="bit-[% g.bit %]" + name="bit-[% g.bit %]" value="1" [% " checked=\"checked\"" IF g.checked %]> - <label for="bit-[% g.bit FILTER html %]">[% g.description FILTER html_light %]</label><br> + <label for="bit-[% g.bit %]">[% g.description FILTER html_light %]</label><br> [% END %] </td> </tr> diff --git a/extensions/BMO/template/en/default/bug/create/create-presentation.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-presentation.html.tmpl index 584b14912..cdbce5c8c 100644 --- a/extensions/BMO/template/en/default/bug/create/create-presentation.html.tmpl +++ b/extensions/BMO/template/en/default/bug/create/create-presentation.html.tmpl @@ -86,7 +86,7 @@ function trySubmit() { <input type="hidden" name="bug_severity" id="bug_severity" value="normal"> <input type="hidden" name="comment" id="comment" value=""> <input type="hidden" name="short_desc" id="short_desc" value=""> - <input type="hidden" name="groups" value="mozilla-corporation-confidential"> + <input type="hidden" name="groups" value="mozilla-corporation-confidential"> <table> <tr> @@ -142,7 +142,7 @@ function trySubmit() { <option value="AM" selected>AM</option> <option value="PM">PM</option> </select> - </td> + </td> </tr> <tr> diff --git a/extensions/BMO/template/en/default/bug/create/create-swag.html.tmpl b/extensions/BMO/template/en/default/bug/create/create-swag.html.tmpl index b2698ae72..f7edccbe1 100644 --- a/extensions/BMO/template/en/default/bug/create/create-swag.html.tmpl +++ b/extensions/BMO/template/en/default/bug/create/create-swag.html.tmpl @@ -34,7 +34,7 @@ <p><strong>Swag Request:</strong> Please use this form to file a request for swag. </p> <ol> - <li>You first need submit a <a href="/enter_bug.cgi?product=Marketing&format=mktgevent">Event Request Form</a>. You'll be asked for the [% terms.bug %] number below.</li> + <li>You first need submit a <a href="/enter_bug.cgi?product=Marketing&format=mktgevent">Event Request Form</a>. You'll be asked for the bug number below.</li> <li>Complete and submit request below.</li> <li>Your request will be reviewed by the appropriate person in the Engagement team.</li> <li>Your swag request will be reviewed and if approved shipped to you from @@ -70,7 +70,7 @@ function validateAndSubmit() { var alert_text = ''; if(!isFilledOut('firstname')) alert_text += "Please enter your first name\n"; if(!isFilledOut('lastname')) alert_text += "Please enter your last name\n"; - if(!isFilledOut('dependson')) alert_text += "Please enter the [% terms.bug %] number for your Event Request Form\n"; + if(!isFilledOut('dependson')) alert_text += "Please enter the bug number for your Event Request Form\n"; if(!isValidEmail(document.getElementById('email').value)) alert_text += "Please enter a valid email address\n"; //Everything required is filled out..try to submit the form! @@ -88,25 +88,25 @@ function validateAndSubmit() { <form method="post" action="post_bug.cgi" id="swagRequestForm" enctype="multipart/form-data" onSubmit="return validateAndSubmit();"> - <input type="hidden" name="format" value="swag"> - <input type="hidden" name="product" value="Marketing"> - <input type="hidden" name="component" value="Swag Requests"> - <input type="hidden" name="rep_platform" value="All"> - <input type="hidden" name="op_sys" value="Other"> - <input type="hidden" name="priority" value="--"> - <input type="hidden" name="version" value="unspecified"> - <input type="hidden" name="bug_severity" id="bug_severity" value="normal"> - <input type="hidden" name="short_desc" id="short_desc" value=""> - <input type="hidden" name="groups" value="mozilla-corporation-confidential"> - + <input type="hidden" name="format" value="swag"> + <input type="hidden" name="product" value="Marketing"> + <input type="hidden" name="component" value="Swag Requests"> + <input type="hidden" name="rep_platform" value="All"> + <input type="hidden" name="op_sys" value="Other"> + <input type="hidden" name="priority" value="--"> + <input type="hidden" name="version" value="unspecified"> + <input type="hidden" name="bug_severity" id="bug_severity" value="normal"> + + <input type="hidden" name="short_desc" id="short_desc" value=""> + <input type="hidden" name="groups" value="mozilla-corporation-confidential"> <table> + <tr> <td align="right"><strong>First Name: <span style="color: red;">*</span></strong></td> <td align="left"> <input type="text" name="firstname" id="firstname" value="" size="20" maxlength="20" /> </td> </tr> - <tr> <td align="right"><strong>Last Name: <span style="color: red;">*</span></strong></td> <td align="left"> @@ -143,7 +143,7 @@ function validateAndSubmit() { </tr> <tr> - <td align="right"><strong>[% terms.Bug %] number assigned to previously- <br>submitted <a href="/enter_bug.cgi?product=Marketing&format=mktgevent">Event Request Form</a>: <span style="color: red;">*</span></strong></td> + <td align="right"><strong>Bug number assigned to previously- <br>submitted <a href="/enter_bug.cgi?product=Marketing&format=mktgevent">Event Request Form</a>: <span style="color: red;">*</span></strong></td> <td colspan="3"><input name="dependson" id="dependson"></td> </tr> diff --git a/extensions/BMO/template/en/default/bug/create/user-message.html.tmpl b/extensions/BMO/template/en/default/bug/create/user-message.html.tmpl index 70a51b9ab..e7cea5d2b 100644 --- a/extensions/BMO/template/en/default/bug/create/user-message.html.tmpl +++ b/extensions/BMO/template/en/default/bug/create/user-message.html.tmpl @@ -62,9 +62,9 @@ the <a href="https://bugzilla.mozilla.org/enter_bug.cgi">full product list</a>. <p> <b>The product you have chosen is for [% terms.bug %] reports and enhancement requests for the -<a href="http://www.bugzilla.org/">[% terms.Bugzilla %] [% terms.bug %] tracking software</a> only.</b> -If your [% terms.bug %] is not reporting that [% terms.Bugzilla %] is broken or that you'd like -a new feature in [% terms.Bugzilla %], your [% terms.bug %] report does not belong in this product. +<a href="http://www.bugzilla.org/">Bugzilla [% terms.bug %] tracking software</a> only.</b> +If your [% terms.bug %] is not reporting that Bugzilla is broken or that you'd like +a new feature in Bugzilla, your [% terms.bug %] report does not belong in this product. [% IF format == "guided" %] See the instructions next to the stop sign above. [% ELSE %] @@ -72,22 +72,22 @@ a new feature in [% terms.Bugzilla %], your [% terms.bug %] report does not belo [% END %] </p> -<p><b>We WILL NOT accept [% terms.bug %] reports for [% terms.Bugzilla %] -installed via the Debian packaging system. If you obtained [% terms.Bugzilla %] from Debian, +<p><b>We WILL NOT accept [% terms.bug %] reports for Bugzilla +installed via the Debian packaging system. If you obtained Bugzilla from Debian, please visit the <a href="http://www.debian.org/support">Debian Support page</a>, -or file a [% terms.bug %] on the <a href="http://bugs.debian.org/cgi-bin/pkgreport.cgi?pkg=bugzilla">Debian -[% terms.Bug %] Tracker</a>.</b> The Debian package maintainer will then determine whether the [% terms.bug %] -is specific to the package or not, and can move the [% terms.bug %] "upstream" if needed.</p> +or file a bug on the <a href="http://bugs.debian.org/cgi-bin/pkgreport.cgi?pkg=bugzilla">Debian +Bug Tracker</a>.</b> The Debian package maintainer will then determine whether the bug +is specific to the package or not, and can move the bug "upstream" if needed.</p> <p> -[% terms.Bugs %] specific to bugzilla.mozilla.org, rather than the [% terms.Bugzilla %] software in +Bugs specific to bugzilla.mozilla.org, rather than the Bugzilla software in general (which is used by many sites), should be filed in the <a href="enter_bug.cgi?product=mozilla.org">mozilla.org product</a>. </p> <p> Please do not file test [% terms.bugs %] or support requests here! You -can test [% terms.Bugzilla %] at +can test Bugzilla at <a href="http://landfill.bugzilla.org/">landfill.bugzilla.org</a> and ask for support in the <a href="news://news.mozilla.org/mozilla.support.bugzilla"> @@ -106,7 +106,7 @@ support-bugzilla@lists.mozilla.org mailing list</a>, or [% UNLESS cloned_bug_id %] Consider using the <a href="enter_bug.cgi?product=[% product.name FILTER html %]&format=guided"> -[% terms.Bugzilla %] Helper</a> instead of this form. +Bugzilla Helper</a> instead of this form. [% END +%] Before reporting a [% terms.bug %], make sure you've read our <a href="http://www.mozilla.org/quality/bug-writing-guidelines.html"> diff --git a/extensions/BMO/template/en/default/global/choose-product.html.tmpl b/extensions/BMO/template/en/default/global/choose-product.html.tmpl index c957edca7..a65605a93 100644 --- a/extensions/BMO/template/en/default/global/choose-product.html.tmpl +++ b/extensions/BMO/template/en/default/global/choose-product.html.tmpl @@ -42,8 +42,7 @@ <center> <hr> -<p><span style="font-family: verdana,helvetica;">Looking for technical support or help getting your site to work with Mozilla? <a href="http://www.mozilla.org/support/">Visit the -mozilla.org support page</a> before filing [% terms.bugs %].</span></p> +<p><span style="font-family: verdana,helvetica;">Looking for technical support or help getting your site to work with Mozilla? <a href="http://www.mozilla.org/support/">Visit the mozilla.org support page</a> before filing bugs.</span></p> <hr> </center> @@ -147,7 +146,7 @@ mozilla.org support page</a> before filing [% terms.bugs %].</span></p> <br> [% IF target == "enter_bug.cgi" AND user.settings.product_chooser.value != 'full_product_chooser' %] -<p align="center">You can choose to get this screen by default when you click "New [% terms.Bug %]" by changing your <a href="userprefs.cgi?tab=settings">preferences</a>.</p> +<p align="center">You can choose to get this screen by default when you click "New Bug" by changing your <a href="userprefs.cgi?tab=settings">preferences</a>.</p> [% END %] [% END %] <br> diff --git a/extensions/BMO/template/en/default/hook/bug/create/create-guided-form.html.tmpl b/extensions/BMO/template/en/default/hook/bug/create/create-guided-form.html.tmpl index 5b58a9637..ee88aac7c 100644 --- a/extensions/BMO/template/en/default/hook/bug/create/create-guided-form.html.tmpl +++ b/extensions/BMO/template/en/default/hook/bug/create/create-guided-form.html.tmpl @@ -1,4 +1,4 @@ - <tr bgcolor="[% tablecolour FILTER html %]"> + <tr bgcolor="[% tablecolour %]"> <td valign="middle" align="right"> <b>Security</b> </td> diff --git a/extensions/BMO/template/en/default/hook/bug/edit-after_custom_fields.html.tmpl b/extensions/BMO/template/en/default/hook/bug/edit-after_custom_fields.html.tmpl index ba6eeb78c..0c68d8e72 100644 --- a/extensions/BMO/template/en/default/hook/bug/edit-after_custom_fields.html.tmpl +++ b/extensions/BMO/template/en/default/hook/bug/edit-after_custom_fields.html.tmpl @@ -49,6 +49,7 @@ [% FOREACH field = Bugzilla.active_custom_fields %] [% NEXT IF NOT user.id AND field.value == "---" %] [% NEXT IF cf_hidden_in_product(field.name, bug.product, bug.component, 2) %] + [% NEXT IF cf_flag_disabled(field.name, bug) %] [% custom_flags.push(field.name) %] <tr id="row_[% field.name FILTER js %]"> <td> </td> diff --git a/extensions/BMO/template/en/default/hook/global/header-additional_header.html.tmpl b/extensions/BMO/template/en/default/hook/global/header-additional_header.html.tmpl index 05276d5f7..0277f3e7e 100644 --- a/extensions/BMO/template/en/default/hook/global/header-additional_header.html.tmpl +++ b/extensions/BMO/template/en/default/hook/global/header-additional_header.html.tmpl @@ -21,7 +21,7 @@ <link rel="shortcut icon" href="extensions/BMO/web/images/bugzilla.png"> [% IF bug %] -<link id="shorturl" rev="canonical" href="https://bugzil.la/[% bug.bug_id FILTER uri %]"> +<link id="shorturl" rev="canonical" href="https://bugzil.la/[% bug.bug_id %]"> [% END %] <style type="text/css"> diff --git a/extensions/BMO/template/en/default/hook/global/user-error-auth_failure_object.html.tmpl b/extensions/BMO/template/en/default/hook/global/user-error-auth_failure_object.html.tmpl new file mode 100644 index 000000000..067347f3b --- /dev/null +++ b/extensions/BMO/template/en/default/hook/global/user-error-auth_failure_object.html.tmpl @@ -0,0 +1,3 @@ +[% IF object == 'group_admins' %] + the group administrators report +[% END %] diff --git a/extensions/BMO/template/en/default/hook/global/user-error-errors.html.tmpl b/extensions/BMO/template/en/default/hook/global/user-error-errors.html.tmpl index 5a3e2bed6..85881aca7 100644 --- a/extensions/BMO/template/en/default/hook/global/user-error-errors.html.tmpl +++ b/extensions/BMO/template/en/default/hook/global/user-error-errors.html.tmpl @@ -34,22 +34,7 @@ [% title = "Invalid Date" %] The date '[% date FILTER html %]' is invalid. -[% ELSIF error == "remo_payment_invalid_product" %] - [% title = "Mozilla Reps Payment Invalid $terms.Bug" %] - You can only attach budget payment information to [% terms.bugs %] under - the product 'Mozilla Reps' and component 'Budget Requests'. - -[% ELSIF error == "remo_payment_bug_edit_denied" %] - [% title = "Mozilla Reps Payment $terms.Bug Edit Denied" %] - You do not have permission to edit [% terms.bug %] '[% bug_id FILTER html %]'. - -[% ELSIF error == "remo_payment_cancel_dupe" %] - [% title = "Already filed payment request" %] - You already used the form to file - <a href="[% urlbase FILTER html %]attachment.cgi?id=[% attachid FILTER uri %]&action=edit"> - attachment [% attachid FILTER uri %]</a>.<br> - <br> - You can either <a href="[% urlbase FILTER html %]page.cgi?id=remo-form-payment.html"> - create a new payment request</a> or [% "go back to $terms.bug $bugid" FILTER bug_link(bugid) FILTER none %]. +[% ELSIF error == "invalid_object" %] + Invalid [% object FILTER html %]: "[% value FILTER html %]" [% END %] diff --git a/extensions/BMO/template/en/default/hook/global/user-error.html.tmpl/auth_failure/permissions.html.tmpl b/extensions/BMO/template/en/default/hook/global/user-error.html.tmpl/auth_failure/permissions.html.tmpl index 346e02373..5f6ca946a 100644 --- a/extensions/BMO/template/en/default/hook/global/user-error.html.tmpl/auth_failure/permissions.html.tmpl +++ b/extensions/BMO/template/en/default/hook/global/user-error.html.tmpl/auth_failure/permissions.html.tmpl @@ -22,7 +22,7 @@ [% IF (group == "canconfirm" OR group == "editbugs") AND !reason %] <p> - If you are attempting to confirm an unconfirmed [% terms.bug %] or edit the fields of a [% terms.bug %], + If you are attempting to confirm an unconfirmed bug or edit the fields of a bug, <a href="http://www.gerv.net/hacking/before-you-mail-gerv.html#bugzilla-permissions">find out how to get the necessary permissions</a>. </p> diff --git a/extensions/BMO/template/en/default/hook/pages/fields-resolution.html.tmpl b/extensions/BMO/template/en/default/hook/pages/fields-resolution.html.tmpl new file mode 100644 index 000000000..4d12ab345 --- /dev/null +++ b/extensions/BMO/template/en/default/hook/pages/fields-resolution.html.tmpl @@ -0,0 +1,13 @@ +<dt> + [% display_value("resolution", "INCOMPLETE") FILTER html %] +</dt> +<dd> + The problem is vaguely described with no steps to reproduce, + or is a support request. The reporter should be directed to the + product's support page for help diagnosing the issue. If there + are only a few comments in the [% terms.bug %], it may be reopened only if + the original reporter provides more info, or confirms someone + else's steps to reproduce. If the [% terms.bug %] is long, when enough info + is provided a new [% terms.bug %] should be filed and the original [% terms.bug %] + marked as a duplicate of it. +</dd> diff --git a/extensions/BMO/template/en/default/hook/reports/menu-end.html.tmpl b/extensions/BMO/template/en/default/hook/reports/menu-end.html.tmpl index b42ff8d2a..6e8463020 100644 --- a/extensions/BMO/template/en/default/hook/reports/menu-end.html.tmpl +++ b/extensions/BMO/template/en/default/hook/reports/menu-end.html.tmpl @@ -31,5 +31,11 @@ %]page.cgi?id=triage_reports.html">Triage Report</a></strong> - Report on UNCONFIRMED [% terms.bugs %] to assist triage. </li> + [% IF user.in_group('editusers') %] + <li> + <strong><a href="[% urlbase FILTER none + %]page.cgi?id=group_admins.html">Group Admins</a></strong> - Group Admins Report + </li> + [% END %] </ul> diff --git a/extensions/BMO/template/en/default/list/list.microsummary.tmpl b/extensions/BMO/template/en/default/list/list.microsummary.tmpl index a095a7e4d..8f6b13cbd 100644 --- a/extensions/BMO/template/en/default/list/list.microsummary.tmpl +++ b/extensions/BMO/template/en/default/list/list.microsummary.tmpl @@ -21,8 +21,9 @@ [% PROCESS global/variables.none.tmpl %] + [% IF searchname %] - [% searchname FILTER html %] ([% bugs.size %]) + [% searchname %] ([% bugs.size %]) [% ELSE %] [% terms.Bug %] List ([% bugs.size %]) [% END %] diff --git a/extensions/BMO/template/en/default/list/server-push.html.tmpl b/extensions/BMO/template/en/default/list/server-push.html.tmpl index 1c1f3cf36..40432a35b 100644 --- a/extensions/BMO/template/en/default/list/server-push.html.tmpl +++ b/extensions/BMO/template/en/default/list/server-push.html.tmpl @@ -34,7 +34,7 @@ <div style="margin-top: 15%; text-align: center;"> <center><img src="extensions/BMO/web/images/mozchomp.gif" alt="" width="160" height="87"></center> - <h1>Please wait while your [% terms.bugs %] are retrieved.</h1> + <h1>Please wait while your bugs are retrieved.</h1> </div> [% IF debug %] diff --git a/extensions/BMO/template/en/default/pages/etiquette.html.tmpl b/extensions/BMO/template/en/default/pages/etiquette.html.tmpl index 8bccaea9d..281057eeb 100644 --- a/extensions/BMO/template/en/default/pages/etiquette.html.tmpl +++ b/extensions/BMO/template/en/default/pages/etiquette.html.tmpl @@ -21,15 +21,15 @@ #%] [% INCLUDE global/header.html.tmpl - title = "$terms.Bugzilla Etiquette" + title = "Bugzilla Etiquette" style = "li { margin: 5px } .heading { font-weight: bold }" %] <p> There's a number of <i lang="fr">faux pas</i> you can commit when using - [% terms.Bugzilla %]. At the very + Bugzilla. At the very least, these will make Mozilla contributors upset at you; if committed enough times they will cause those contributors to demand the disabling of your - [% terms.Bugzilla %] account. So, ignore this advice at your peril. + Bugzilla account. So, ignore this advice at your peril. </p> <p> @@ -47,14 +47,14 @@ <li> <span class="heading">No pointless comments</span>. Unless you have something constructive and helpful to say, do not add a - comment to a [% terms.bug %]. In [% terms.bugs %] where there is a heated debate going on, you + comment to a bug. In bugs where there is a heated debate going on, you should be even more inclined not to add a comment. Unless you have something new to contribute, - then the [% terms.bug %] owner is aware of all the issues, and will make a judgement - as to what to do. If you agree the [% terms.bug %] should be fixed, vote for it. + then the bug owner is aware of all the issues, and will make a judgement + as to what to do. If you agree the bug should be fixed, vote for it. Additional "I see this too" or "It works for me" comments are unnecessary unless they are on a different platform or a significantly different build. - Constructive and helpful thoughts unrelated to the topic of the [% terms.bug %] + Constructive and helpful thoughts unrelated to the topic of the bug should go in the appropriate <a href="http://www.mozilla.org/about/forums/">newsgroup</a>. </li> @@ -63,8 +63,8 @@ <span class="heading">No obligation</span>. "Open Source" is not the same as "the developers must do my bidding." Everyone here wants to help, but the only person who has any - <i>obligation</i> to fix the [% terms.bugs %] you want fixed is you. Therefore, you - should not act as if you expect someone to fix a [% terms.bug %] by a particular date + <i>obligation</i> to fix the bugs you want fixed is you. Therefore, you + should not act as if you expect someone to fix a bug by a particular date or release. Aggressive or repeated demands will not be received well and will almost certainly diminish the impact and interest in your suggestions. @@ -80,17 +80,17 @@ <i>things</i>, not <i>people</i>. Examples of things include: interfaces, algorithms, and schedules. Examples of people include: developers, designers and users. <b>Attacking a person may result in you being banned - from [% terms.Bugzilla %].</b> + from Bugzilla.</b> </li> <li> <span class="heading">No private email</span>. - Unless the [% terms.bug %] owner or another respected project contributor has asked you + Unless the bug owner or another respected project contributor has asked you to email them with specific information, please place all information - relating to [% terms.bugs %] - in the [% terms.bug %] itself. Do not send them by private email; no-one else can read + relating to bugs + in the bug itself. Do not send them by private email; no-one else can read them if you do that, and they'll probably just get ignored. If a file - is too big for [% terms.Bugzilla %], add a comment giving the file size and contents + is too big for Bugzilla, add a comment giving the file size and contents and ask what to do. </li> </ol> @@ -99,19 +99,19 @@ <ol> <li> - <span class="heading">No messing with other people's [% terms.bugs %]</span>. - Unless you are the [% terms.bug %] assignee, or have some say over the use of their + <span class="heading">No messing with other people's bugs</span>. + Unless you are the bug assignee, or have some say over the use of their time, never change the Priority or Target Milestone fields. If in doubt, - do not change the fields of [% terms.bugs %] you do not own - add a comment + do not change the fields of bugs you do not own - add a comment instead, suggesting the change. </li> <li> <span class="heading">No whining about decisions</span>. - If a respected project contributor has marked a [% terms.bug %] as INVALID, then it is + If a respected project contributor has marked a bug as INVALID, then it is invalid. Someone filing another duplicate of it does not change this. Unless you have further important evidence, do not post a comment arguing that an - INVALID or WONTFIX [% terms.bug %] should be reopened. + INVALID or WONTFIX bug should be reopened. </li> </ol> @@ -129,7 +129,7 @@ <p> If you see someone not following these rules, the first step is, as an exception to guideline 1.4, to make them aware of this document by <em>private</em> mail. - Flaming people publically in [% terms.bugs %] violates guidelines 1.1 and 1.3. In the case of + Flaming people publically in bugs violates guidelines 1.1 and 1.3. In the case of persistent offending you should report the matter to <a href="mailto:gerv@mozilla.org">Gerv</a>. </p> @@ -141,7 +141,7 @@ <p> Other useful documents: - <a href="page.cgi?id=bug-writing.html">The [% terms.Bug %] Writing Guidelines</a>. + <a href="page.cgi?id=bug-writing.html">The Bug Writing Guidelines</a>. </p> [% INCLUDE global/footer.html.tmpl %] diff --git a/extensions/BMO/template/en/default/pages/group_admins.html.tmpl b/extensions/BMO/template/en/default/pages/group_admins.html.tmpl new file mode 100644 index 000000000..a55b6e2ad --- /dev/null +++ b/extensions/BMO/template/en/default/pages/group_admins.html.tmpl @@ -0,0 +1,53 @@ +[%# The contents of this file are subject to the Mozilla Public + # License Version 1.1 (the "License"); you may not use this file + # except in compliance with the License. You may obtain a copy of + # the License at http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS + # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + # implied. See the License for the specific language governing + # rights and limitations under the License. + # + # The Original Code is the BMO Extension + # + # The Initial Developer of the Original Code is the Mozilla Foundation + # Portions created by the Initial Developers are Copyright (C) 2011 the + # Initial Developer. All Rights Reserved. + # + # Contributor(s): + # David Lawrence <dkl@mozilla.com> + #%] + +[% INCLUDE global/header.html.tmpl + title = "Group Admins Report" + style_urls = [ "extensions/BMO/web/styles/reports.css" ] +%] + +[% IF groups.size > 0 %] + <table border="0" cellspacing="0" id="report" width="100%"> + <tr id="report-header"> + <th align="left">Name</th> + <th align="left">Admins</th> + </tr> + + [% FOREACH group = groups %] + [% count = loop.count() %] + <tr class="report_item [% count % 2 == 1 ? "report_row_odd" : "report_row_even" %]"> + <td> + [% group.name FILTER html %] + </td> + <td> + [% FOREACH admin = group.admins %] + [% INCLUDE global/user.html.tmpl who = admin %][% ", " UNLESS loop.last %] + [% END %] + </td> + </tr> + [% END %] + </table> +[% ELSE %] + <p> + No groups found. + </p> +[% END %] + +[% INCLUDE global/footer.html.tmpl %] diff --git a/extensions/BMO/template/en/default/pages/triage_reports.html.tmpl b/extensions/BMO/template/en/default/pages/triage_reports.html.tmpl index a7f26e86d..023dc4791 100644 --- a/extensions/BMO/template/en/default/pages/triage_reports.html.tmpl +++ b/extensions/BMO/template/en/default/pages/triage_reports.html.tmpl @@ -59,7 +59,7 @@ var selected_components = [ <input type="hidden" name="id" value="triage_reports.html"> <input type="hidden" name="action" value="run"> -Show UNCONFIRMED [% terms.bugs %] with: +Show UNCONFIRMED bugs with: <table id="triage_form"> <tr> @@ -149,7 +149,7 @@ Show UNCONFIRMED [% terms.bugs %] with: </p> <table border="0" cellspacing="0" id="report" width="100%"> <tr id="report-header"> - <th>[% terms.Bug %] / Date</th> + <th>Bug / Date</th> <th>Summary</th> <th>Reporter / Commenter</th> <th>Comment Date</th> @@ -190,7 +190,7 @@ Show UNCONFIRMED [% terms.bugs %] with: [% ELSE %] <p> - No [% terms.bugs %] found. + No bugs found. </p> [% END %] diff --git a/extensions/BMO/template/en/default/pages/user_activity.html.tmpl b/extensions/BMO/template/en/default/pages/user_activity.html.tmpl index 904f0ba62..dd16595ab 100644 --- a/extensions/BMO/template/en/default/pages/user_activity.html.tmpl +++ b/extensions/BMO/template/en/default/pages/user_activity.html.tmpl @@ -96,7 +96,7 @@ [% IF incomplete_data %] <p> - There used to be an issue in <a href="http://www.bugzilla.org/">[% terms.Bugzilla %]</a> + There used to be an issue in <a href="http://www.bugzilla.org/">Bugzilla</a> which caused activity data to be lost if there were a large number of cc's or dependencies. That has been fixed, but some data was already lost in your activity table that could not be regenerated. The changes that @@ -110,7 +110,7 @@ <tr id="report-header"> <th>Who</th> <th>When</th> - <th>[% terms.Bug %]</th> + <th>Bug</th> <th>What</th> <th>Removed</th> <th>Added</th> @@ -131,9 +131,9 @@ [% "</tr><tr>" IF loop.index > 0 %] <td> [% IF change.attachid %] - <a href="attachment.cgi?id=[% change.attachid FILTER uri %]">Attachment #[% change.attachid FILTER html %]</a> + <a href="attachment.cgi?id=[% change.attachid %]">Attachment #[% change.attachid %]</a> [% ELSIF change.comment.defined && change.fieldname == 'longdesc' %] - [% "Comment $change.comment.count" FILTER bug_link(operation.bug, comment_num => change.comment.count) FILTER none %] + [% "Comment $change.comment.count" FILTER bug_link(operation.bug, comment_num => change.comment.count) %] [% ELSE %] [%+ field_descs.${change.fieldname} FILTER html %] [% END %] diff --git a/extensions/BMO/web/js/edit_bug.js b/extensions/BMO/web/js/edit_bug.js index 6f0bc4587..5fc2ab6f7 100644 --- a/extensions/BMO/web/js/edit_bug.js +++ b/extensions/BMO/web/js/edit_bug.js @@ -54,3 +54,18 @@ function bmo_show_tracking_flags() { } } } + +// -- make attachment table, comments, new comment textarea equal widths + +YAHOO.util.Event.onDOMReady(function() { + var comment_tables = Dom.getElementsByClassName('bz_comment_table', 'table', 'comments'); + if (comment_tables.length) { + var comment_width = comment_tables[0].getElementsByTagName('td')[0].clientWidth + 'px'; + var attachment_table = Dom.get('attachment_table'); + if (attachment_table) + attachment_table.style.width = comment_width; + var new_comment = Dom.get('comment'); + if (new_comment) + new_comment.style.width = comment_width; + } +}); diff --git a/extensions/BMO/web/js/edituser_menu.js b/extensions/BMO/web/js/edituser_menu.js new file mode 100644 index 000000000..9ce78d9ce --- /dev/null +++ b/extensions/BMO/web/js/edituser_menu.js @@ -0,0 +1,26 @@ +var admin_usermenu; + +YAHOO.util.Event.onDOMReady(function() { + admin_usermenu = new YAHOO.widget.Menu('admin_usermenu', { position : 'dynamic' }); + admin_usermenu.addItems([ + { text: 'Edit', url: '#', target: '_new' }, + { text: 'Activity', url: '#', target: '_new' }, + { text: 'Mail', url: '#', target: '_new' } + ]); + admin_usermenu.render(document.body); +}); + +function show_admin_username(event, id, email) { + if (!admin_usermenu) + return; + admin_usermenu.getItem(0).cfg.setProperty('url', 'editusers.cgi?action=edit&userid=' + id); + admin_usermenu.getItem(1).cfg.setProperty('url', + 'page.cgi?id=user_activity.html&action=run' + + '&from=' + YAHOO.util.Date.format(new Date(new Date() - (1000 * 60 * 60 * 24 * 14)), {format: '%Y-%m-%d'}) + + '&to=' + YAHOO.util.Date.format(new Date(), {format: '%Y-%m-%d'}) + + '&who=' + escape(email)); + admin_usermenu.getItem(2).cfg.setProperty('url', 'mailto:' + escape(email)); + admin_usermenu.cfg.setProperty('xy', YAHOO.util.Event.getXY(event)); + admin_usermenu.show(); +} + diff --git a/extensions/BMO/web/styles/reports.css b/extensions/BMO/web/styles/reports.css new file mode 100644 index 000000000..3106a6295 --- /dev/null +++ b/extensions/BMO/web/styles/reports.css @@ -0,0 +1,37 @@ +.hidden { + display: none; +} + +#triage_form th { + text-align: left; +} + +#product, #component { + width: 20em; +} + +#report tr.bugitem:hover { + background: #ccccff; +} + +#report td { + padding: 1px 10px 1px 10px; +} + +#report-header { + background: #dddddd; +} + +.report_row_odd { + background-color: #F7F7F7; + color: #000000; +} + +.report_row_even { + background-color: #FFFFFF; + color: #000000; +} + +tr.report_item:hover { + background-color: #ccccff; +} diff --git a/extensions/BzAPI/template/en/default/config.json.tmpl b/extensions/BzAPI/template/en/default/config.json.tmpl index f83dee5fb..d567c6c55 100644 --- a/extensions/BzAPI/template/en/default/config.json.tmpl +++ b/extensions/BzAPI/template/en/default/config.json.tmpl @@ -127,7 +127,7 @@ OLDATTACH2NEW = { [% FOREACH cl IN classifications %] [% cl_name_for.${cl.id} = cl.name %] "[% cl.name FILTER json %]": { - "id": [% cl.id FILTER json %], + "id": [% cl.id %], "description": "[% cl.description FILTER json %]", "products": [ [% FOREACH product IN cl.products %] @@ -142,7 +142,7 @@ OLDATTACH2NEW = { "product": { [% FOREACH product = products %] "[% product.name FILTER json %]": { - "id": [% product.id FILTER json %], + "id": [% product.id %], "description": "[% product.description FILTER json %]", "is_active": [% product.isactive ? "true" : "false" %], "is_permitting_unconfirmed": [% product.allows_unconfirmed ? "true" : "false" %], @@ -152,16 +152,15 @@ OLDATTACH2NEW = { "component": { [% FOREACH component = product.components %] "[% component.name FILTER json %]": { - "id": [% component.id FILTER json %], + "id": [% component.id %], [% IF show_flags %] "flag_type": [ [% flag_types = - component.flag_types.bug.merge(component.flag_types.attachment) %] + component.flag_types(is_active=>1).bug.merge(component.flag_types(is_active=>1).attachment) %] [%-# "first" flag used to get commas right; can't use loop.last() in case # last flag is inactive %] [% first = 1 %] [% FOREACH flag_type = flag_types %] - [% NEXT UNLESS flag_type.is_active %] [% all_visible_flag_types.${flag_type.id} = flag_type %] [% ',' UNLESS first %][% flag_type.id FILTER json %][% first = 0 %] [% END %]], @@ -187,7 +186,7 @@ OLDATTACH2NEW = { "group": [ [% FOREACH group = product.groups_valid %] - [% group.id FILTER json %][% ',' UNLESS loop.last() %] + [% group.id %][% ',' UNLESS loop.last() %] [% END %] ] }[% ',' UNLESS loop.last() %] @@ -196,7 +195,7 @@ OLDATTACH2NEW = { "group": { [% FOREACH group = product.groups_valid %] - "[% group.id FILTER json %]": { + "[% group.id %]": { "name": "[% group.name FILTER json %]", "description": "[% group.description FILTER json %]", "is_accepting_bugs": [% group.is_bug_group ? 'true' : 'false' %], @@ -208,15 +207,15 @@ OLDATTACH2NEW = { [% IF show_flags %] "flag_type": { [% FOREACH flag_type = all_visible_flag_types.values.sort('name') %] - "[%+ flag_type.id FILTER json %]": { + "[%+ flag_type.id %]": { "name": "[% flag_type.name FILTER json %]", "description": "[% flag_type.description FILTER json %]", [% IF user.in_group("editcomponents") %] [% IF flag_type.request_group_id %] - "request_group": [% flag_type.request_group_id FILTER json %], + "request_group": [% flag_type.request_group_id %], [% END %] [% IF flag_type.grant_group_id %] - "grant_group": [% flag_type.grant_group_id FILTER json %], + "grant_group": [% flag_type.grant_group_id %], [% END %] [% END %] "is_for_bugs": [% flag_type.target_type == "bug" ? 'true' : 'false' %], @@ -310,7 +309,7 @@ OLDATTACH2NEW = { [% IF newname.match("^cf_") %] "is_on_bug_entry": [% item.enter_bug ? 'true' : 'false' %], [% END %] - "type": [% item.type || type_id_for.$newname || 0 FILTER json %] + "type": [% item.type || type_id_for.$newname || 0 %] }[% ',' UNLESS loop.last() %] [% END %] } diff --git a/extensions/ComponentWatching/template/en/default/account/prefs/component_watch.html.tmpl b/extensions/ComponentWatching/template/en/default/account/prefs/component_watch.html.tmpl index c3247078a..057a32e36 100644 --- a/extensions/ComponentWatching/template/en/default/account/prefs/component_watch.html.tmpl +++ b/extensions/ComponentWatching/template/en/default/account/prefs/component_watch.html.tmpl @@ -113,19 +113,19 @@ You are currently watching: [% FOREACH watch IN watches %] <tr> [% IF (watch.component) %] - <td><input type="checkbox" name="del_[% watch.product.id FILTER uri %]_[% watch.component.id FILTER uri %]" value="1"></td> + <td><input type="checkbox" name="del_[% watch.product.id %]_[% watch.component.id %]" value="1"></td> <td>[% watch.component.product.name FILTER html %]</td> <td> - <a href="buglist.cgi?product=[% watch.product.name FILTER uri -%] - &component=[% watch.component.name FILTER uri %]&resolution=---"> + <a href="buglist.cgi?product=[% watch.product.name FILTER url ~%] + &component=[% watch.component.name FILTER url %]&resolution=---"> [% watch.component.name FILTER html %] </a> </td> [% ELSE %] - <td><input type="checkbox" name="del_[% watch.product.id FILTER uri %]" value="1"></td> + <td><input type="checkbox" name="del_[% watch.product.id %]" value="1"></td> <td>[% watch.product.name FILTER html %]</td> <td> - <a href="describecomponents.cgi?product=[% watch.product.name FILTER uri %]"> + <a href="describecomponents.cgi?product=[% watch.product.name FILTER url %]"> __Any__ </a> </td> diff --git a/extensions/Example/Extension.pm b/extensions/Example/Extension.pm index 4498d2b22..ef20a28f0 100644 --- a/extensions/Example/Extension.pm +++ b/extensions/Example/Extension.pm @@ -211,12 +211,15 @@ sub search_operator_field_override { sub _component_nonchanged { my $original = shift; - my ($invocant, $args) = @_; + my $invocant = shift; + + my %func_args = @_; + $invocant->$original(%func_args); - $invocant->$original($args); # Actually, it does not change anything in the result, # just an example. - $args->{term} = $args->{term} . " OR 1=2"; + my ($term) = @func_args{qw(term)}; + $$term = $$term . " OR 1=2"; } sub bugmail_recipients { @@ -261,14 +264,9 @@ sub config_modify_panels { my $auth_params = $panels->{'auth'}->{params}; my ($info_class) = grep($_->{name} eq 'user_info_class', @$auth_params); my ($verify_class) = grep($_->{name} eq 'user_verify_class', @$auth_params); - + push(@{ $info_class->{choices} }, 'CGI,Example'); push(@{ $verify_class->{choices} }, 'Example'); - - push(@$auth_params, { name => 'param_example', - type => 't', - default => 0, - checker => \&check_numeric }); } sub db_schema_abstract_schema { @@ -456,26 +454,6 @@ sub install_update_db { # $dbh->bz_add_index('example', 'example_new_column_idx', [qw(value)]); } -sub install_update_db_fielddefs { - my $dbh = Bugzilla->dbh; -# $dbh->bz_add_column('fielddefs', 'example_column', -# {TYPE => 'MEDIUMTEXT', NOTNULL => 1, DEFAULT => ''}); -} - -sub job_map { - my ($self, $args) = @_; - - my $job_map = $args->{job_map}; - - # This adds the named class (an instance of TheSchwartz::Worker) as a - # handler for when a job is added with the name "some_task". - $job_map->{'some_task'} = 'Bugzilla::Extension::Example::Job::SomeClass'; - - # Schedule a job like this: - # my $queue = Bugzilla->job_queue(); - # $queue->insert('some_task', { some_parameter => $some_variable }); -} - sub mailer_before_send { my ($self, $args) = @_; diff --git a/extensions/Example/lib/Config.pm b/extensions/Example/lib/Config.pm index 75db22957..a126e82df 100644 --- a/extensions/Example/lib/Config.pm +++ b/extensions/Example/lib/Config.pm @@ -25,8 +25,6 @@ use warnings; use Bugzilla::Config::Common; -our $sortkey = 5000; - sub get_param_list { my ($class) = @_; diff --git a/extensions/GuidedBugEntry/template/en/default/guided/guided.html.tmpl b/extensions/GuidedBugEntry/template/en/default/guided/guided.html.tmpl index 403b63a6e..8f8817344 100644 --- a/extensions/GuidedBugEntry/template/en/default/guided/guided.html.tmpl +++ b/extensions/GuidedBugEntry/template/en/default/guided/guided.html.tmpl @@ -27,7 +27,7 @@ [% PROCESS global/variables.none.tmpl %] [% PROCESS global/header.html.tmpl - title = "Enter A $terms.Bug" + title = "Enter A Bug" javascript_urls = [ 'extensions/GuidedBugEntry/web/js/products.js', 'extensions/GuidedBugEntry/web/js/guided.js', @@ -41,8 +41,8 @@ <input id="yui-history-field" type="hidden"> <noscript> -You require JavaScript to use this [% terms.bug %] entry form.<br><br> -Please use the <a href="enter_bug.cgi?format=__default__">advanced [% terms.bug %] entry form</a>. +You require JavaScript to use this bug entry form.<br><br> +Please use the <a href="enter_bug.cgi?format=__default__">advanced bug entry form</a>. </noscript> <div id="loading" class="hidden"> @@ -62,7 +62,7 @@ YAHOO.util.Dom.removeClass('loading', 'hidden'); <div id="advanced"> <a id="advanced_img" href="enter_bug.cgi?format=__default__"><img src="extensions/GuidedBugEntry/web/images/advanced.png" width="16" height="16" border="0"></a> - <a id="advanced_link" href="enter_bug.cgi?format=__default__">Switch to the advanced [% terms.bug %] entry form</a> + <a id="advanced_link" href="enter_bug.cgi?format=__default__">Switch to the advanced bug entry form</a> </div> <script type="text/javascript"> @@ -94,7 +94,7 @@ dupes.setLabels( [% BLOCK page_title %] <div id="page_title"> - <h2>Enter A [% terms.Bug %]</h2> + <h2>Enter A Bug</h2> <h3>Step [% step_number FILTER html %] of 3</h3> </div> [% END %] @@ -145,7 +145,7 @@ dupes.setLabels( <td class="product_img"> <a href="javascript:void(0)" [% IF onclick %] - onclick="[% onclick FILTER none %]" + onclick="[% onclick %]" [% ELSE %] onclick="product.select('[% name FILTER js %]')" [% END %] @@ -156,7 +156,7 @@ dupes.setLabels( <h2> <a href="javascript:void(0)" [% IF onclick %] - onclick="[% onclick FILTER none %]" + onclick="[% onclick %]" [% ELSE %] onclick="product.select('[% name FILTER js %]')" [% END %] @@ -260,14 +260,14 @@ dupes.setLabels( </div> </td> <td width="100%"> - • <a href="http://input.mozilla.org/feedback/">Provide other feedback about Firefox</a><br> - • <a href="http://input.mozilla.org/feedback/#sad">Report an issue with a web site that I use</a><br> - • <a href="enter_bug.cgi?format=guided&product=Core">Report an issue with Firefox on a site that I've developed</a><br> + • <a href="http://input.mozilla.org/feedback/">Provide other feedback about Firefox</a><br> + • <a href="http://input.mozilla.org/feedback/#sad">Report an issue with a web site that I use</a><br> + • <a href="enter_bug.cgi?format=guided&product=Core">Report an issue with Firefox on a site that I've developed</a><br> </td> </tr> </table> <h3> - None of the above; my [% terms.bug %] is in: + None of the above; my bug is in: </h3> [% END %] @@ -275,14 +275,14 @@ dupes.setLabels( <tr> <td> <div class="exit_img"> - <a href="[% href FILTER none %]" + <a href="[% href %]" ><img src="extensions/GuidedBugEntry/web/images/[% icon FILTER uri %]" width="32" height="32" ></a> </div> </td> <td width="100%"> <h2> - <a href="[% href FILTER none %]">[% name FILTER html %]</a> + <a href="[% href %]">[% name FILTER html %]</a> </h2> [% desc FILTER html %] </td> @@ -359,7 +359,7 @@ Product: <b><span id="dupes_product_name">?</span></b>: <li>Please fill out this form clearly, precisely and in as much detail as you can manage.</li> <li>Please report only a single problem at a time.</li> <li><a href="https://developer.mozilla.org/en/Bug_writing_guidelines" target="_blank">These guidelines</a> -explain how to write effective [% terms.bug %] reports.</li> +explain how to write effective bug reports.</li> </ul> <table id="bugForm" cellspacing="0"> @@ -512,7 +512,7 @@ explain how to write effective [% terms.bug %] reports.</li> <tr class="odd"> <td> </td> <td colspan="2" id="submitTD"> - <input type="submit" id="submit" value="Submit [% terms.Bug %]"> + <input type="submit" id="submit" value="Submit Bug"> </td> </tr> diff --git a/extensions/GuidedBugEntry/web/js/guided.js b/extensions/GuidedBugEntry/web/js/guided.js index f600dbb21..e3efd6446 100644 --- a/extensions/GuidedBugEntry/web/js/guided.js +++ b/extensions/GuidedBugEntry/web/js/guided.js @@ -162,8 +162,7 @@ var product = { // show support message if (products[productName] && products[productName].support) { - Dom.get("product_support_message").innerHTML = - YAHOO.lang.escapeHTML(products[productName].support); + Dom.get("product_support_message").innerHTML = products[productName].support; Dom.removeClass("product_support", "hidden"); } else { Dom.addClass("product_support", "hidden"); @@ -251,6 +250,7 @@ var dupes = { this._elList = Dom.get('dupes_list'); Event.onBlur(this._elSummary, this._onSummaryBlur); + Event.addListener(this._elSummary, 'input', this._onSummaryBlur); Event.addListener(this._elSummary, 'keydown', this._onSummaryKeyDown); Event.addListener(this._elSummary, 'keyup', this._onSummaryKeyUp); Event.addListener(this._elSearch, 'click', this._doSearch); diff --git a/extensions/GuidedBugEntry/web/style/guided.css b/extensions/GuidedBugEntry/web/style/guided.css index f4d8ec90d..b0c766d11 100644 --- a/extensions/GuidedBugEntry/web/style/guided.css +++ b/extensions/GuidedBugEntry/web/style/guided.css @@ -81,6 +81,8 @@ .exits { width: 600px; margin-bottom: 10px; + border: 1px solid #aaa; + border-radius: 5px; } .exits td { diff --git a/extensions/InlineHistory/Config.pm b/extensions/InlineHistory/Config.pm new file mode 100644 index 000000000..dd4002856 --- /dev/null +++ b/extensions/InlineHistory/Config.pm @@ -0,0 +1,31 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for +# the specific language governing rights and limitations under the License. +# +# The Original Code is the InlineHistory Bugzilla Extension; +# Derived from the Bugzilla Tweaks Addon. +# +# The Initial Developer of the Original Code is the Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2011 the Initial +# Developer. All Rights Reserved. +# +# Contributor(s): +# Johnathan Nightingale <johnath@mozilla.com> +# Ehsan Akhgari <ehsan@mozilla.com> +# Byron Jones <glob@mozilla.com> +# +# ***** END LICENSE BLOCK ***** + +package Bugzilla::Extension::InlineHistory; +use strict; + +use constant NAME => 'InlineHistory'; + +__PACKAGE__->NAME; diff --git a/extensions/InlineHistory/Extension.pm b/extensions/InlineHistory/Extension.pm new file mode 100644 index 000000000..63a67304b --- /dev/null +++ b/extensions/InlineHistory/Extension.pm @@ -0,0 +1,183 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for +# the specific language governing rights and limitations under the License. +# +# The Original Code is the InlineHistory Bugzilla Extension; +# Derived from the Bugzilla Tweaks Addon. +# +# The Initial Developer of the Original Code is the Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2011 the Initial +# Developer. All Rights Reserved. +# +# Contributor(s): +# Johnathan Nightingale <johnath@mozilla.com> +# Ehsan Akhgari <ehsan@mozilla.com> +# Byron Jones <glob@mozilla.com> +# +# ***** END LICENSE BLOCK ***** + +package Bugzilla::Extension::InlineHistory; +use strict; +use base qw(Bugzilla::Extension); + +use Bugzilla::User::Setting; +use Bugzilla::Constants; +use Bugzilla::Attachment; + +our $VERSION = '1.4'; + +sub template_before_process { + my ($self, $args) = @_; + my $file = $args->{'file'}; + my $vars = $args->{'vars'}; + my $user = Bugzilla->user; + my $dbh = Bugzilla->dbh; + + return unless $user && $user->id && $user->settings; + return unless $user->settings->{'inline_history'}->{'value'} eq 'on'; + + # in the header we just need to set the var, to ensure the css and + # javascript get included + if ($file eq 'bug/show-header.html.tmpl') { + $vars->{'ih_activity'} = 1; + return; + } elsif ($file ne 'bug/edit.html.tmpl') { + return; + } + + # note: bug/edit.html.tmpl doesn't support multiple bugs + my $bug_id = exists $vars->{'bugs'} + ? $vars->{'bugs'}[0]->id + : $vars->{'bug'}->id; + + # build bug activity + my ($activity) = Bugzilla::Bug::GetBugActivity($bug_id); + $activity = _add_duplicates($bug_id, $activity); + + # augment and tweak + foreach my $operation (@$activity) { + # make operation.who an object + $operation->{who} = Bugzilla::User->new({ name => $operation->{who} }); + for (my $i = 0; $i < scalar(@{$operation->{changes}}); $i++) { + my $change = $operation->{changes}->[$i]; + + # make an attachment object + if ($change->{attachid}) { + $change->{attach} = Bugzilla::Attachment->new($change->{attachid}); + } + + # empty resolutions are displayed as --- by default + # make it explicit here to enable correct display of the change + if ($change->{fieldname} eq 'resolution') { + $change->{removed} = '---' if $change->{removed} eq ''; + $change->{added} = '---' if $change->{added} eq ''; + } + + # make boolean fields true/false instead of 1/0 + my ($table, $field) = ('bugs', $change->{fieldname}); + if ($field =~ /^([^\.]+)\.(.+)$/) { + ($table, $field) = ($1, $2); + } + my $column = $dbh->bz_column_info($table, $field); + if ($column && $column->{TYPE} eq 'BOOLEAN') { + $change->{removed} = ''; + $change->{added} = $change->{added} ? 'true' : 'false'; + } + + # split multiple flag changes (must be processed last) + if ($change->{fieldname} eq 'flagtypes.name') { + my @added = split(/, /, $change->{added}); + my @removed = split(/, /, $change->{removed}); + next if scalar(@added) <= 1 && scalar(@removed) <= 1; + # remove current change + splice(@{$operation->{changes}}, $i, 1); + # restructure into added/removed for each flag + my %flags; + foreach my $added (@added) { + my ($value, $name) = $added =~ /^((.+).)$/; + $flags{$name}{added} = $value; + $flags{$name}{removed} |= ''; + } + foreach my $removed (@removed) { + my ($value, $name) = $removed =~ /^((.+).)$/; + $flags{$name}{added} |= ''; + $flags{$name}{removed} = $value; + } + # clone current change, modify and insert + foreach my $flag (sort keys %flags) { + my $flag_change = {}; + foreach my $key (keys %$change) { + $flag_change->{$key} = $change->{$key}; + } + $flag_change->{removed} = $flags{$flag}{removed}; + $flag_change->{added} = $flags{$flag}{added}; + splice(@{$operation->{changes}}, $i, 0, $flag_change); + } + $i--; + } + } + } + + $vars->{'ih_activity'} = $activity; +} + +sub _add_duplicates { + # insert 'is a dupe of this bug' comment to allow js to display + # as activity + + my ($bug_id, $activity) = @_; + + my $dbh = Bugzilla->dbh; + my $sth = $dbh->prepare(" + SELECT profiles.login_name, " . + $dbh->sql_date_format('bug_when', '%Y.%m.%d %H:%i:%s') . ", + extra_data, + thetext + FROM longdescs + INNER JOIN profiles ON profiles.userid = longdescs.who + WHERE bug_id = ? + AND ( + type = ? + OR thetext LIKE '%has been marked as a duplicate of this%' + ) + ORDER BY bug_when + "); + $sth->execute($bug_id, CMT_HAS_DUPE); + + while (my($who, $when, $dupe_id, $the_text) = $sth->fetchrow_array) { + if (!$dupe_id) { + next unless $the_text =~ / (\d+) has been marked as a duplicate of this/; + $dupe_id = $1; + } + my $entry = { + 'when' => $when, + 'who' => $who, + 'changes' => [ + { + 'removed' => '', + 'added' => $dupe_id, + 'attachid' => undef, + 'fieldname' => 'dupe', + 'dupe' => 1, + } + ], + }; + push @$activity, $entry; + } + + return [ sort { $a->{when} cmp $b->{when} } @$activity ]; +} + +sub install_before_final_checks { + my ($self, $args) = @_; + add_setting('inline_history', ['on', 'off'], 'off'); +} + +__PACKAGE__->NAME; diff --git a/extensions/InlineHistory/README b/extensions/InlineHistory/README new file mode 100644 index 000000000..f5aaf163f --- /dev/null +++ b/extensions/InlineHistory/README @@ -0,0 +1,10 @@ +InlineHistory inserts bug activity inline with the comments when viewing a bug. +It was derived from the Bugzilla Tweaks Addon by Ehasn Akhgari. + +For technical and performance reasons it is only available to logged in users, +and is enabled by a User Preference. + +It works with an unmodified install of Bugzilla 4.0 and 4.2. + +If you have modified your show_bug template, the javascript in +web/inline-history.js may need to be updated to suit your installation. diff --git a/extensions/InlineHistory/template/en/default/hook/bug/comments-aftercomments.html.tmpl b/extensions/InlineHistory/template/en/default/hook/bug/comments-aftercomments.html.tmpl new file mode 100644 index 000000000..4af08dca8 --- /dev/null +++ b/extensions/InlineHistory/template/en/default/hook/bug/comments-aftercomments.html.tmpl @@ -0,0 +1,135 @@ +[%# ***** BEGIN LICENSE BLOCK ***** + # Version: MPL 1.1 + # + # The contents of this file are subject to the Mozilla Public License Version + # 1.1 (the "License"); you may not use this file except in compliance with + # the License. You may obtain a copy of the License at + # http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS IS" basis, + # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + # for the specific language governing rights and limitations under the + # License. + # + # The Original Code is the InlineHistory Bugzilla Extension; + # Derived from the Bugzilla Tweaks Addon. + # + # The Initial Developer of the Original Code is the Mozilla Foundation. + # Portions created by the Initial Developer are Copyright (C) 2011 the + # Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Johnathan Nightingale <johnath@mozilla.com> + # Ehsan Akhgari <ehsan@mozilla.com> + # Byron Jones <glob@mozilla.com> + # + # ***** END LICENSE BLOCK ***** + #%] + +[% IF ih_activity %] +[%# this div exists to allow bugzilla-tweaks to detect when we're active %] +<div id="inline-history-ext"></div> + +<script> + var ih_activity = new Array(); + var ih_activity_flags = new Array(); + var ih_activity_sort_order = '[% user.settings.comment_sort_order.value FILTER js %]'; + [% FOREACH operation = ih_activity %] + var html = ''; + [% has_cc = 0 %] + [% has_flag = 0 %] + [% FOREACH change = operation.changes %] + [%# track flag changes %] + [% IF change.fieldname == 'flagtypes.name' && change.added != '' %] + var item = new Array(5); + item[0] = '[% operation.who.login FILTER js %]'; + item[1] = '[% operation.when FILTER time FILTER js %]'; + item[2] = '[% change.attachid FILTER js %]'; + item[3] = '[% change.added FILTER js %]'; + item[4] = '[% operation.who.identity FILTER js %]'; + ih_activity_flags.push(item); + [% has_flag = 1 %] + [% END %] + + [%# wrap CC changes in a span for toggling visibility %] + [% IF change.fieldname == 'cc' %] + html += '<span class="ih_cc">'; + [% has_cc = 1 %] + [% END %] + + [%# make attachment changes better %] + [% IF change.attachid %] + html += '<a ' + + 'href="attachment.cgi?action=edit&id=[% change.attachid FILTER none %]" ' + + 'title="[% change.attach.description FILTER js %]" ' + + 'class="[% "bz_obsolete" IF change.attach.isobsolete %]"' + + '>Attachment #[% change.attachid FILTER none %]</a> - '; + [% END %] + + [%# display duplicates as history rather than comments %] + [% IF change.dupe %] + html += 'Duplicate of this [% terms.bug %]: '; + [% ELSE %] + html += '[% field_descs.${change.fieldname} FILTER js %]: '; + [% END %] + + [% IF change.removed != '' %] + [% IF change.added == '' %] + html += '<span class="ih_deleted">'; + [% END %] + [% PROCESS add_change value = change.removed, is_old = 1 %] + [% IF change.added == '' %] + html += '</span>'; + [% ELSE %] + html += ' ➔ '; + [% END %] + [% END %] + [% PROCESS add_change value = change.added, is_old = 0 %] + [% "html += '<br>';" UNLESS loop.last %] + + [% IF change.fieldname == 'cc' %] + html += '</span>'; + [% END %] + [% END %] + var item = new Array(7); + item[0] = '[% operation.who.login FILTER js %]'; + item[1] = '[% operation.when FILTER time FILTER js %]'; + item[2] = html; + item[3] = '<div class="bz_comment_head">' + + '<span class="bz_comment_user">' + + '[% INCLUDE global/user.html.tmpl who = operation.who FILTER js %]' + + '</span>' + + '<span class="bz_comment_time"> ' + item[1] + ' </span>' + + '</div>'; + item[4] = [% IF has_cc && (operation.changes.size == 1) %]true[% ELSE %]false[% END %]; + item[5] = [% IF change.dupe %][% change.added FILTER js %][% ELSE %]0[% END %]; + item[6] = [% IF has_flag %]true[% ELSE %]false[% END %]; + ih_activity[[% loop.index %]] = item; + [% END %] + inline_history.init(); +</script> +[% END %] + +[% BLOCK add_change %] + html += '[%~%] + [% '<span class="old">' IF is_old %] + [% IF change.fieldname == 'estimated_time' || + change.fieldname == 'remaining_time' || + change.fieldname == 'work_time' %] + [% PROCESS formattimeunit time_unit = value FILTER html FILTER js %] + [% ELSIF change.fieldname == 'blocked' || + change.fieldname == 'dependson' || + change.fieldname == 'dupe' %] + [% value FILTER bug_list_link FILTER js %] + [% ELSIF change.fieldname == 'assigned_to' || + change.fieldname == 'reporter' || + change.fieldname == 'qa_contact' || + change.fieldname == 'cc' || + change.fieldname == 'flagtypes.name' %] + [% display_value(change.fieldname, value) FILTER email FILTER js %] + [% ELSE %] + [% display_value(change.fieldname, value) FILTER html FILTER js %] + [% END %] + [% '</span>' IF is_old %] + [%~ %]'; +[% END %] diff --git a/extensions/InlineHistory/template/en/default/hook/bug/show-header-end.html.tmpl b/extensions/InlineHistory/template/en/default/hook/bug/show-header-end.html.tmpl new file mode 100644 index 000000000..221175105 --- /dev/null +++ b/extensions/InlineHistory/template/en/default/hook/bug/show-header-end.html.tmpl @@ -0,0 +1,33 @@ +[%# ***** BEGIN LICENSE BLOCK ***** + # Version: MPL 1.1 + # + # The contents of this file are subject to the Mozilla Public License Version + # 1.1 (the "License"); you may not use this file except in compliance with + # the License. You may obtain a copy of the License at + # http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS IS" basis, + # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + # for the specific language governing rights and limitations under the + # License. + # + # The Original Code is the InlineHistory Bugzilla Extension; + # Derived from the Bugzilla Tweaks Addon. + # + # The Initial Developer of the Original Code is the Mozilla Foundation. + # Portions created by the Initial Developer are Copyright (C) 2011 the + # Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Johnathan Nightingale <johnath@mozilla.com> + # Ehsan Akhgari <ehsan@mozilla.com> + # Byron Jones <glob@mozilla.com> + # + # ***** END LICENSE BLOCK ***** + #%] + +[% IF ih_activity %] + [% style_urls.push('extensions/InlineHistory/web/style.css') %] + [% javascript_urls.push('extensions/InlineHistory/web/inline-history.js') %] +[% END %] + diff --git a/extensions/InlineHistory/template/en/default/hook/global/setting-descs-settings.none.tmpl b/extensions/InlineHistory/template/en/default/hook/global/setting-descs-settings.none.tmpl new file mode 100644 index 000000000..852dac22f --- /dev/null +++ b/extensions/InlineHistory/template/en/default/hook/global/setting-descs-settings.none.tmpl @@ -0,0 +1,31 @@ +[%# ***** BEGIN LICENSE BLOCK ***** + # Version: MPL 1.1 + # + # The contents of this file are subject to the Mozilla Public License Version + # 1.1 (the "License"); you may not use this file except in compliance with + # the License. You may obtain a copy of the License at + # http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS IS" basis, + # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + # for the specific language governing rights and limitations under the + # License. + # + # The Original Code is the InlineHistory Bugzilla Extension; + # Derived from the Bugzilla Tweaks Addon. + # + # The Initial Developer of the Original Code is the Mozilla Foundation. + # Portions created by the Initial Developer are Copyright (C) 2011 the + # Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Johnathan Nightingale <johnath@mozilla.com> + # Ehsan Akhgari <ehsan@mozilla.com> + # Byron Jones <glob@mozilla.com> + # + # ***** END LICENSE BLOCK ***** + #%] + +[% + setting_descs.inline_history = "When viewing a $terms.bug, show all $terms.bug activity", +%] diff --git a/extensions/InlineHistory/web/inline-history.js b/extensions/InlineHistory/web/inline-history.js new file mode 100644 index 000000000..9fb860e3c --- /dev/null +++ b/extensions/InlineHistory/web/inline-history.js @@ -0,0 +1,396 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + * the specific language governing rights and limitations under the License. + * + * The Original Code is the InlineHistory Bugzilla Extension; + * Derived from the Bugzilla Tweaks Addon. + * Derived from the Bugzilla Tweaks Addon. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 the Initial + * Developer. All Rights Reserved. + * + * Contributor(s): + * Johnathan Nightingale <johnath@mozilla.com> + * Ehsan Akhgari <ehsan@mozilla.com> + * Byron Jones <glob@mozilla.com> + * + * ***** END LICENSE BLOCK ***** + */ + +var inline_history = { + _ccDivs: null, + _hasAttachmentFlags: false, + _hasBugFlags: false, + + init: function() { + Dom = YAHOO.util.Dom; + + // remove 'has been marked as a duplicate of this bug' comments + var reDuplicate = /\*\*\* \S+ \d+ has been marked as a duplicate of this/; + var reBugId = /show_bug\.cgi\?id=(\d+)/; + var comments = Dom.getElementsByClassName("bz_comment", 'div', 'comments'); + for (var i = 1, il = comments.length; i < il; i++) { + var textDiv = Dom.getElementsByClassName('bz_comment_text', 'pre', comments[i]); + if (textDiv) { + var match = reDuplicate.exec(textDiv[0].textContent || textDiv[0].innerText); + if (match) { + // grab the comment and bug number from the element + var comment = comments[i]; + var number = comment.id.substr(1); + var time = this.trim(Dom.getElementsByClassName('bz_comment_time', 'span', comment)[0].innerHTML); + var dupeId = 0; + match = reBugId.exec(Dom.get('comment_text_' + number).innerHTML); + if (match) + dupeId = match[1]; + // remove the element + comment.parentNode.removeChild(comment); + // update the html for the history item to include the comment number + if (dupeId == 0) + continue; + for (var j = 0, jl = ih_activity.length; j < jl; j++) { + var item = ih_activity[j]; + if (item[5] == dupeId && item[1] == time) { + // insert comment number and link into the header + item[3] = item[3].substr(0, item[3].length - 6) // remove trailing </div> + // add comment number + + '<span class="bz_comment_number" id="c' + number + '">' + + '<a href="#c' + number + '">Comment ' + number + '</a>' + + '</span>' + + '</div>'; + break; + } + } + } + } + } + + // ensure new items are placed immediately after the last comment + var commentDivs = Dom.getElementsByClassName('bz_comment', 'div', 'comments'); + if (!commentDivs.length) return; + var lastCommentDiv = commentDivs[commentDivs.length - 1]; + + // insert activity into the correct location + var commentTimes = Dom.getElementsByClassName('bz_comment_time', 'span', 'comments'); + for (var i = 0, il = ih_activity.length; i < il; i++) { + var item = ih_activity[i]; + // item[0] : who + // item[1] : when + // item[2] : change html + // item[3] : header html + // item[4] : bool; cc-only + // item[5] : int; dupe bug id (or 0) + // item[6] : bool; is flag + var user = item[0]; + var time = item[1]; + + var reachedEnd = false; + var start_index = ih_activity_sort_order == 'newest_to_oldest_desc_first' ? 1 : 0; + for (var j = start_index, jl = commentTimes.length; j < jl; j++) { + var commentHead = commentTimes[j].parentNode; + var mainUser = Dom.getElementsByClassName('email', 'a', commentHead)[0].href.substr(7); + var text = commentTimes[j].textContent || commentTimes[j].innerText; + var mainTime = this.trim(text); + + if (ih_activity_sort_order == 'oldest_to_newest' ? time > mainTime : time < mainTime) { + if (j < commentTimes.length - 1) { + continue; + } else { + reachedEnd = true; + } + } + + var inline = (mainUser == user && time == mainTime); + var currentDiv = document.createElement("div"); + + // place ih_cc class on parent container if it's the only child + var containerClass = ''; + if (item[4]) { + item[2] = item[2].replace('"ih_cc"', '""'); + containerClass = 'ih_cc'; + } + + if (inline) { + // assume that the change was made by the same user + commentHead.parentNode.appendChild(currentDiv); + currentDiv.innerHTML = item[2]; + Dom.addClass(currentDiv, 'ih_inlinehistory'); + Dom.addClass(currentDiv, containerClass); + if (item[6]) + this.setFlagChangeID(item, commentHead.parentNode.id); + + } else { + // the change was made by another user + if (!reachedEnd) { + var parentDiv = commentHead.parentNode; + var previous = this.previousElementSibling(parentDiv); + if (previous && previous.className.indexOf("ih_history") >= 0) { + currentDiv = this.previousElementSibling(parentDiv); + } else { + parentDiv.parentNode.insertBefore(currentDiv, parentDiv); + } + } else { + var parentDiv = commentHead.parentNode; + var next = this.nextElementSibling(parentDiv); + if (next && next.className.indexOf("ih_history") >= 0) { + currentDiv = this.nextElementSibling(parentDiv); + } else { + lastCommentDiv.parentNode.insertBefore(currentDiv, lastCommentDiv.nextSibling); + } + } + + var itemHtml = '<div class="ih_history_item ' + containerClass + '" ' + + 'id="h' + i + '">' + + item[3] + item[2] + + '</div>'; + + if (ih_activity_sort_order == 'oldest_to_newest') { + currentDiv.innerHTML = currentDiv.innerHTML + itemHtml; + } else { + currentDiv.innerHTML = itemHtml + currentDiv.innerHTML; + } + currentDiv.setAttribute("class", "bz_comment ih_history"); + if (item[6]) + this.setFlagChangeID(item, 'h' + i); + } + break; + } + } + + // find comment blocks which only contain cc changes, shift the ih_cc + var historyDivs = Dom.getElementsByClassName('ih_history', 'div', 'comments'); + for (var i = 0, il = historyDivs.length; i < il; i++) { + var historyDiv = historyDivs[i]; + var itemDivs = Dom.getElementsByClassName('ih_history_item', 'div', historyDiv); + var ccOnly = true; + for (var j = 0, jl = itemDivs.length; j < jl; j++) { + if (!Dom.hasClass(itemDivs[j], 'ih_cc')) { + ccOnly = false; + break; + } + } + if (ccOnly) { + for (var j = 0, jl = itemDivs.length; j < jl; j++) { + Dom.removeClass(itemDivs[j], 'ih_cc'); + } + Dom.addClass(historyDiv, 'ih_cc'); + } + } + + if (this._hasAttachmentFlags) + this.linkAttachmentFlags(); + if (this._hasBugFlags) + this.linkBugFlags(); + + ih_activity = undefined; + ih_activity_flags = undefined; + + this._ccDivs = Dom.getElementsByClassName('ih_cc', '', 'comments'); + this.hideCC(); + YAHOO.util.Event.onDOMReady(this.addCCtoggler); + }, + + setFlagChangeID: function(changeItem, id) { + // put the ID for the change into ih_activity_flags + for (var i = 0, il = ih_activity_flags.length; i < il; i++) { + var flagItem = ih_activity_flags[i]; + // flagItem[0] : who.login + // flagItem[1] : when + // flagItem[2] : attach id + // flagItem[3] : flag + // flagItem[4] : who.identity + // flagItem[5] : change div id + if (flagItem[0] == changeItem[0] && flagItem[1] == changeItem[1]) { + // store the div + flagItem[5] = id; + // tag that we have flags to process + if (flagItem[2]) { + this._hasAttachmentFlags = true; + } else { + this._hasBugFlags = true; + } + // don't break as there may be multiple flag changes at once + } + } + }, + + linkAttachmentFlags: function() { + var rows = Dom.get('attachment_table').getElementsByTagName('tr'); + for (var i = 0, il = rows.length; i < il; i++) { + + // deal with attachments with flags only + var tr = rows[i]; + if (!tr.id || tr.id == 'a0') + continue; + var attachFlagTd = Dom.getElementsByClassName('bz_attach_flags', 'td', tr); + if (attachFlagTd.length == 0) + continue; + attachFlagTd = attachFlagTd[0]; + + // get the attachment id + var attachId = 0; + var anchors = tr.getElementsByTagName('a'); + for (var j = 0, jl = anchors.length; j < jl; j++) { + var match = anchors[j].href.match(/attachment\.cgi\?id=(\d+)/); + if (match) { + attachId = match[1]; + break; + } + } + if (!attachId) + continue; + + var html = ''; + + // there may be multiple flags, split by <br> + var attachFlags = attachFlagTd.innerHTML.split('<br>'); + for (var j = 0, jl = attachFlags.length; j < jl; j++) { + var match = attachFlags[j].match(/^\s*(<span.+\/span>):([^\?\-\+]+[\?\-\+])([\s\S]*)/); + if (!match) continue; + var setterSpan = match[1]; + var flag = this.trim(match[2].replace('\u2011', '-', 'g')); + var requestee = this.trim(match[3]); + var requesteeLogin = ''; + + match = setterSpan.match(/title="([^"]+)"/); + if (!match) continue; + var setterIdentity = this.htmlDecode(match[1]); + + if (requestee) { + match = requestee.match(/title="([^"]+)"/); + if (!match) continue; + requesteeLogin = this.htmlDecode(match[1]); + match = requesteeLogin.match(/<([^>]+)>/); + if (!match) continue; + requesteeLogin = match[1]; + } + + var flagValue = requestee ? flag + '(' + requesteeLogin + ')' : flag; + // find the id for this change + var found = false; + for (var k = 0, kl = ih_activity_flags.length; k < kl; k++) { + flagItem = ih_activity_flags[k]; + if ( + flagItem[2] == attachId + && flagItem[3] == flagValue + && flagItem[4] == setterIdentity + ) { + html += + setterSpan + ': ' + + '<a href="#' + flagItem[5] + '">' + flag + '</a>' + + requestee + '<br>'; + found = true; + break; + } + } + if (!found) { + // something went wrong, insert the flag unlinked + html += attachFlags[j] + '<br>'; + } + } + + if (html) + attachFlagTd.innerHTML = html; + } + }, + + linkBugFlags: function() { + var rows = Dom.get('flags').getElementsByTagName('tr'); + for (var i = 0, il = rows.length; i < il; i++) { + var cells = rows[i].getElementsByTagName('td'); + if (!cells[1]) continue; + + var match = cells[0].innerHTML.match(/title="([^"]+)"/); + if (!match) continue; + var setterIdentity = this.htmlDecode(match[1]); + + var flagValue = cells[2].getElementsByTagName('select'); + if (!flagValue.length) continue; + flagValue = flagValue[0].value; + + var flagLabel = cells[1].getElementsByTagName('label'); + if (!flagLabel.length) continue; + flagLabel = flagLabel[0]; + var flagName = this.trim(flagLabel.innerHTML).replace('\u2011', '-', 'g'); + + for (var j = 0, jl = ih_activity_flags.length; j < jl; j++) { + flagItem = ih_activity_flags[j]; + if ( + !flagItem[2] + && flagItem[3] == flagName + flagValue + && flagItem[4] == setterIdentity + ) { + flagLabel.innerHTML = + '<a href="#' + flagItem[5] + '">' + flagName + '</a>'; + break; + } + } + } + }, + + hideCC: function() { + Dom.addClass(this._ccDivs, 'ih_hidden'); + }, + + showCC: function() { + Dom.removeClass(this._ccDivs, 'ih_hidden'); + }, + + addCCtoggler: function() { + var ul = Dom.getElementsByClassName('bz_collapse_expand_comments'); + if (ul.length == 0) + return; + ul = ul[0]; + var a = document.createElement('a'); + a.href = 'javascript:void(0)'; + a.id = 'ih_toggle_cc'; + YAHOO.util.Event.addListener(a, 'click', function(e) { + if (Dom.get('ih_toggle_cc').innerHTML == 'Show CC Changes') { + a.innerHTML = 'Hide CC Changes'; + inline_history.showCC(); + } else { + a.innerHTML = 'Show CC Changes'; + inline_history.hideCC(); + } + }); + a.innerHTML = 'Show CC Changes'; + var li = document.createElement('li'); + li.appendChild(a); + ul.appendChild(li); + }, + + previousElementSibling: function(el) { + if (el.previousElementSibling) + return el.previousElementSibling; + while (el = el.previousSibling) { + if (el.nodeType == 1) + return el; + } + }, + + nextElementSibling: function(el) { + if (el.nextElementSibling) + return el.nextElementSibling; + while (el = el.nextSibling) { + if (el.nodeType == 1) + return el; + } + }, + + htmlDecode: function(v) { + var e = document.createElement('div'); + e.innerHTML = v; + return e.childNodes.length == 0 ? '' : e.childNodes[0].nodeValue; + }, + + trim: function(s) { + return s.replace(/^\s+|\s+$/g, ''); + } +} diff --git a/extensions/InlineHistory/web/style.css b/extensions/InlineHistory/web/style.css new file mode 100644 index 000000000..bca3a197b --- /dev/null +++ b/extensions/InlineHistory/web/style.css @@ -0,0 +1,54 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + * the specific language governing rights and limitations under the License. + * + * The Original Code is the InlineHistory Bugzilla Extension; + * Derived from the Bugzilla Tweaks Addon. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 the Initial + * Developer. All Rights Reserved. + * + * Contributor(s): + * Johnathan Nightingale <johnath@mozilla.com> + * Ehsan Akhgari <ehsan@mozilla.com> + * Byron Jones <glob@mozilla.com> + * + * ***** END LICENSE BLOCK ***** + */ + +.ih_history { + background: none !important; + color: #444; +} + +.ih_inlinehistory { + font-weight: normal; + font-size: small; + color: #444; + border-top: 1px dotted #C8C8BA; + padding-top: 5px; +} + +.bz_comment.ih_history { + padding: 5px 5px 0px 5px +} + +.ih_history_item { + margin-bottom: 5px; +} + +.ih_hidden { + display: none; +} + +.ih_deleted { + text-decoration: line-through; +} diff --git a/extensions/REMO/Config.pm b/extensions/REMO/Config.pm new file mode 100644 index 000000000..625e2afd9 --- /dev/null +++ b/extensions/REMO/Config.pm @@ -0,0 +1,34 @@ +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the REMO Bugzilla Extension. +# +# The Initial Developer of the Original Code is Mozilla Foundation +# Portions created by the Initial Developer are Copyright (C) 2011 the +# Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Byron Jones <glob@mozilla.com> +# David Lawrence <dkl@mozilla.com> + +package Bugzilla::Extension::REMO; +use strict; + +use constant NAME => 'REMO'; + +use constant REQUIRED_MODULES => [ +]; + +use constant OPTIONAL_MODULES => [ +]; + +__PACKAGE__->NAME; diff --git a/extensions/REMO/Extension.pm b/extensions/REMO/Extension.pm new file mode 100644 index 000000000..a0091281b --- /dev/null +++ b/extensions/REMO/Extension.pm @@ -0,0 +1,184 @@ +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the REMO Bugzilla Extension. +# +# The Initial Developer of the Original Code is Mozilla Foundation +# Portions created by the Initial Developer are Copyright (C) 2011 the +# Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Byron Jones <glob@mozilla.com> +# David Lawrence <dkl@mozilla.com> + +package Bugzilla::Extension::REMO; +use strict; +use base qw(Bugzilla::Extension); + +use Bugzilla::Constants; +use Bugzilla::Util qw(trick_taint trim detaint_natural); +use Bugzilla::Token; +use Bugzilla::Error; + +our $VERSION = '0.01'; + +sub page_before_template { + my ($self, $args) = @_; + my $page = $args->{'page_id'}; + my $vars = $args->{'vars'}; + + if ($page eq 'remo-form-payment.html') { + _remo_form_payment($vars); + } +} + +sub _remo_form_payment { + my ($vars) = @_; + my $input = Bugzilla->input_params; + + my $user = Bugzilla->login(LOGIN_REQUIRED); + + if ($input->{'action'} eq 'commit') { + my $template = Bugzilla->template; + my $cgi = Bugzilla->cgi; + my $dbh = Bugzilla->dbh; + + my $bug_id = $input->{'bug_id'}; + detaint_natural($bug_id); + my $bug = Bugzilla::Bug->check($bug_id); + + # Detect if the user already used the same form to submit again + my $token = trim($input->{'token'}); + if ($token) { + my ($creator_id, $date, $old_attach_id) = Bugzilla::Token::GetTokenData($token); + if (!$creator_id + || $creator_id != $user->id + || $old_attach_id !~ "^remo_form_payment:") + { + # The token is invalid. + ThrowUserError('token_does_not_exist'); + } + + $old_attach_id =~ s/^remo_form_payment://; + if ($old_attach_id) { + ThrowUserError('remo_payment_cancel_dupe', + { bugid => $bug_id, attachid => $old_attach_id }); + } + } + + # Make sure the user can attach to this bug + if (!$bug->user->{'canedit'}) { + ThrowUserError("remo_payment_bug_edit_denied", + { bug_id => $bug->id }); + } + + # Make sure the bug is under the correct product/component + if ($bug->product ne 'Mozilla Reps' + || $bug->component ne 'Budget Requests') + { + ThrowUserError('remo_payment_invalid_product'); + } + + my ($timestamp) = $dbh->selectrow_array("SELECT NOW()"); + + $dbh->bz_start_transaction; + + # Create the comment to be added based on the form fields from rep-payment-form + my $comment; + $template->process("pages/comment-remo-form-payment.txt.tmpl", $vars, \$comment) + || ThrowTemplateError($template->error()); + $bug->add_comment($comment, { isprivate => 0 }); + + # Attach expense report + # FIXME: Would be nice to be able to have the above prefilled comment and + # the following attachments all show up under a single comment. But the longdescs + # table can only handle one attach_id per comment currently. At least only one + # email is sent the way it is done below. + my $attachment; + if (defined $cgi->upload('expenseform')) { + # Determine content-type + my $content_type = $cgi->uploadInfo($cgi->param('expenseform'))->{'Content-Type'}; + + $attachment = Bugzilla::Attachment->create( + { bug => $bug, + creation_ts => $timestamp, + data => $cgi->upload('expenseform'), + description => 'Expense Form', + filename => scalar $cgi->upload('expenseform'), + ispatch => 0, + isprivate => 0, + isurl => 0, + mimetype => $content_type, + store_in_file => 0, + }); + + # Insert comment for attachment + $bug->add_comment('', { isprivate => 0, + type => CMT_ATTACHMENT_CREATED, + extra_data => $attachment->id }); + } + + # Attach receipts file + if (defined $cgi->upload("receipts")) { + # Determine content-type + my $content_type = $cgi->uploadInfo($cgi->param("receipts"))->{'Content-Type'}; + + $attachment = Bugzilla::Attachment->create( + { bug => $bug, + creation_ts => $timestamp, + data => $cgi->upload('receipts'), + description => "Receipts", + filename => scalar $cgi->upload("receipts"), + ispatch => 0, + isprivate => 0, + isurl => 0, + mimetype => $content_type, + store_in_file => 0, + }); + + # Insert comment for attachment + $bug->add_comment('', { isprivate => 0, + type => CMT_ATTACHMENT_CREATED, + extra_data => $attachment->id }); + } + + $bug->update($timestamp); + + if ($token) { + trick_taint($token); + $dbh->do('UPDATE tokens SET eventdata = ? WHERE token = ?', undef, + ("remo_form_payment:" . $attachment->id, $token)); + } + + $dbh->bz_commit_transaction; + + # Define the variables and functions that will be passed to the UI template. + $vars->{'attachment'} = $attachment; + $vars->{'bugs'} = [ new Bugzilla::Bug($bug_id) ]; + $vars->{'header_done'} = 1; + $vars->{'contenttypemethod'} = 'autodetect'; + + my $recipients = { 'changer' => $user }; + $vars->{'sent_bugmail'} = Bugzilla::BugMail::Send($bug_id, $recipients); + + print $cgi->header(); + # Generate and return the UI (HTML page) from the appropriate template. + $template->process("attachment/created.html.tmpl", $vars) + || ThrowTemplateError($template->error()); + exit; + } + else { + $vars->{'token'} = issue_session_token('remo_form_payment:'); + } +} + +__PACKAGE__->NAME; diff --git a/extensions/BMO/template/en/default/bug/create/comment-mozreps.txt.tmpl b/extensions/REMO/template/en/default/bug/create/comment-mozreps.txt.tmpl index 6c9d7c6b7..29544d669 100644 --- a/extensions/BMO/template/en/default/bug/create/comment-mozreps.txt.tmpl +++ b/extensions/REMO/template/en/default/bug/create/comment-mozreps.txt.tmpl @@ -8,7 +8,7 @@ # implied. See the License for the specific language governing # rights and limitations under the License. # - # The Original Code is the BMO Bugzilla Extension. + # The Original Code is the REMO Bugzilla Extension. # # The Initial Developer of the Original Code is the Mozilla Foundation # Portions created by the Initial Developers are Copyright (C) 2011 the diff --git a/extensions/BMO/template/en/default/bug/create/comment-remo-budget.txt.tmpl b/extensions/REMO/template/en/default/bug/create/comment-remo-budget.txt.tmpl index 9486c56fe..9486c56fe 100644 --- a/extensions/BMO/template/en/default/bug/create/comment-remo-budget.txt.tmpl +++ b/extensions/REMO/template/en/default/bug/create/comment-remo-budget.txt.tmpl diff --git a/extensions/BMO/template/en/default/bug/create/comment-remo-swag.txt.tmpl b/extensions/REMO/template/en/default/bug/create/comment-remo-swag.txt.tmpl index 0b98178b2..985a8924d 100644 --- a/extensions/BMO/template/en/default/bug/create/comment-remo-swag.txt.tmpl +++ b/extensions/REMO/template/en/default/bug/create/comment-remo-swag.txt.tmpl @@ -30,23 +30,27 @@ Requester info: -Requester name: [% cgi.param('firstname') %][% " " %][% cgi.param('lastname') %] +First name: [% cgi.param('firstname') %] +Last name: [% cgi.param('lastname') %] Wiki user profile: [% cgi.param('wikiprofile') %] +Event name: [% cgi.param('eventname') %] Event wiki page: [% cgi.param('wikipage') %] -Estimated Attendance: [% cgi.param('attendance') %] +Estimated attendance: [% cgi.param('attendance') %] Shipping details: -Ship swag before: [% cgi.param('shipdate') %] - -[%+ cgi.param("shiptofirstname") +%] [%+ cgi.param("shiptolastname") +%] -[%+ cgi.param("shiptoaddress") +%] -[%+ cgi.param("shiptoaddress2") +%] -[%+ cgi.param("shiptocity") +%] [%+ cgi.param("shiptostate") +%] [%+ cgi.param("shiptopcode") +%] -[%+ cgi.param("shiptocountry") %] +Ship swag before: [% cgi.param('cf_due_date') %] +First name: [% cgi.param("shiptofirstname") %] +Last name: [% cgi.param("shiptolastname") %] +Address line 1: [% cgi.param("shiptoaddress1") %] +Address line 2: [% cgi.param("shiptoaddress2") %] +City: [% cgi.param("shiptocity") %] +State/Region: [% cgi.param("shiptostate") %] +Postal code: [% cgi.param("shiptopcode") %] +Country: [% cgi.param("shiptocountry") %] Phone: [% cgi.param("shiptophone") %] -[%+ IF cgi.param("shiptoidrut") %]Personal ID/RUT: [% cgi.param("shiptoidrut") %][% END %] +[%+ IF cgi.param("shiptoidrut") %]Custom reference: [% cgi.param("shiptoidrut") %][% END %] Addition information for delivery person: [%+ cgi.param('shipadditional') %] diff --git a/extensions/BMO/template/en/default/bug/create/create-mozreps.html.tmpl b/extensions/REMO/template/en/default/bug/create/create-mozreps.html.tmpl index 914e1f54d..8b126f9dd 100644 --- a/extensions/BMO/template/en/default/bug/create/create-mozreps.html.tmpl +++ b/extensions/REMO/template/en/default/bug/create/create-mozreps.html.tmpl @@ -8,7 +8,7 @@ # implied. See the License for the specific language governing # rights and limitations under the License. # - # The Original Code is the BMO Bugzilla Extension. + # The Original Code is the REMO Bugzilla Extension. # # The Initial Developer of the Original Code is the Mozilla Foundation # Portions created by the Initial Developers are Copyright (C) 2011 the @@ -21,7 +21,7 @@ [% PROCESS global/header.html.tmpl title = "Mozilla Reps - Application Form" - style_urls = [ "extensions/BMO/web/styles/moz_reps.css" ] + style_urls = [ "extensions/REMO/web/styles/moz_reps.css" ] %] [% USE Bugzilla %] @@ -92,12 +92,12 @@ function submitForm() { <table id="reps-form"> <tr class="odd"> - <th>First Name:[% mandatory FILTER html %]</th> + <th>First Name:[% mandatory %]</th> <td><input id="first_name" name="first_name" size="40" placeholder="John"></td> </tr> <tr class="even"> - <th>Last Name:[% mandatory FILTER html %]</th> + <th>Last Name:[% mandatory %]</th> <td><input id="last_name" name="last_name" size="40" placeholder="Doe"></td> </tr> @@ -107,7 +107,7 @@ function submitForm() { </tr> <tr class="even"> - <th>Sex:[% mandatory FILTER html %]</th> + <th>Sex:[% mandatory %]</th> <td> <select id="sex" name="sex"> <option value="Male">Male</option> @@ -118,12 +118,12 @@ function submitForm() { </tr> <tr class="odd"> - <th>City:[% mandatory FILTER html %]</th> + <th>City:[% mandatory %]</th> <td><input id="city" name="city" size="40" placeholder="Your city"></td> </tr> <tr class="even"> - <th>Country:[% mandatory FILTER html %]</th> + <th>Country:[% mandatory %]</th> <td><input id="country" name="country" size="40" placeholder="Your country"></td> </tr> @@ -161,17 +161,17 @@ function submitForm() { </tr> <tr class="odd"> - <th>Languages Spoken:[% mandatory FILTER html %]</th> + <th>Languages Spoken:[% mandatory %]</th> <td><input id="languages" name="languages" size="40"></td> </tr> <tr class="even"> - <th>How did you learn about Mozilla Reps?[% mandatory FILTER html %]</th> + <th>How did you learn about Mozilla Reps?[% mandatory %]</th> <td><input id="learn" name="learn" size="40"></td> </tr> <tr class="odd"> - <th colspan="2">What motivates you most about joining Mozilla Reps?[% mandatory FILTER html %]</th> + <th colspan="2">What motivates you most about joining Mozilla Reps?[% mandatory %]</th> </tr> <tr class="odd"> <td colspan="2"><textarea id="motivation" name="motivation" rows="4"></textarea></td> @@ -187,7 +187,7 @@ function submitForm() { <tr class="odd"> <th> I have read the - <a href="http://www.mozilla.com/en-US/privacy-policy" target="_blank">Mozilla Privacy Policy</a>:[% mandatory FILTER html %] + <a href="http://www.mozilla.com/en-US/privacy-policy" target="_blank">Mozilla Privacy Policy</a>:[% mandatory %] </th> <td><input id="privacy" type="checkbox"></td> </tr> diff --git a/extensions/BMO/template/en/default/bug/create/create-remo-budget.html.tmpl b/extensions/REMO/template/en/default/bug/create/create-remo-budget.html.tmpl index 0aa18e41d..267b25e3a 100644 --- a/extensions/BMO/template/en/default/bug/create/create-remo-budget.html.tmpl +++ b/extensions/REMO/template/en/default/bug/create/create-remo-budget.html.tmpl @@ -23,12 +23,14 @@ [% PROCESS global/header.html.tmpl title = "Mozilla Reps Budget Request Form" - style_urls = [ 'extensions/BMO/web/styles/moz_reps.css' ] - javascript_urls = [ 'extensions/BMO/web/js/form_validate.js', + style_urls = [ 'extensions/REMO/web/styles/moz_reps.css' ] + javascript_urls = [ 'extensions/REMO/web/js/form_validate.js', 'js/util.js', 'js/field.js' ] %] +[% IF user.in_group("mozilla-reps") %] + <p>These requests will only be visible to the person who submitted the request, any persons designated in the CC line, and authorized members of the Mozilla Rep team.</p> @@ -245,4 +247,8 @@ function togglePaymentInfo (e) { Thanks for contacting us. </p> +[% ELSE %] + <p>Sorry, you do not have access to this page.</p> +[% END %] + [% PROCESS global/footer.html.tmpl %] diff --git a/extensions/BMO/template/en/default/bug/create/create-remo-swag.html.tmpl b/extensions/REMO/template/en/default/bug/create/create-remo-swag.html.tmpl index 0b15240fd..ae24e667a 100644 --- a/extensions/BMO/template/en/default/bug/create/create-remo-swag.html.tmpl +++ b/extensions/REMO/template/en/default/bug/create/create-remo-swag.html.tmpl @@ -23,24 +23,23 @@ [% PROCESS global/header.html.tmpl title = "Mozilla Reps Swag Request Form" - javascript_urls = [ 'extensions/BMO/web/js/swag.js', - 'extensions/BMO/web/js/form_validate.js', + javascript_urls = [ 'extensions/REMO/web/js/swag.js', + 'extensions/REMO/web/js/form_validate.js', 'js/field.js', 'js/util.js' ] - style_urls = [ "extensions/BMO/web/styles/moz_reps.css", - "skins/custom/calendar.css" ] + style_urls = [ "extensions/REMO/web/styles/moz_reps.css" ] yui = [ 'calendar' ] %] +[% IF user.in_group("mozilla-reps") %] + <p>These requests will only be visible to the person who submitted the request, any persons designated in the CC line, and authorized members of the Mozilla Rep team.</p> <script language="javascript" type="text/javascript"> function trySubmit() { - var firstname = document.getElementById('firstname').value; - var lastname = document.getElementById('lastname').value; - var requester = firstname + ' ' + lastname; - var shortdesc = 'Swag Request - ' + requester; + var eventname = document.getElementById('eventname').value; + var shortdesc = 'Swag Request - ' + eventname; document.getElementById('short_desc').value = shortdesc; return true; } @@ -50,11 +49,12 @@ function validateAndSubmit() { if(!isFilledOut('firstname')) alert_text += "Please enter your first name\n"; if(!isFilledOut('lastname')) alert_text += "Please enter your last name\n"; if(!isFilledOut('wikiprofile')) alert_text += "Please enter your wiki user profile\n"; + if(!isFilledOut('eventname')) alert_text += "Please enter your event name\n"; if(!isFilledOut('wikipage')) alert_text += "Please enter the event wiki page.\n"; if(!isFilledOut('attendance')) alert_text += "Please enter the estimated attendance.\n"; if(!isFilledOut('shiptofirstname')) alert_text += "Please enter the shipping first name\n"; if(!isFilledOut('shiptolastname')) alert_text += "Please enter the shipping last name\n"; - if(!isFilledOut('shiptoaddress')) alert_text += "Please enter the ship to address\n"; + if(!isFilledOut('shiptoaddress1')) alert_text += "Please enter the ship to address\n"; if(!isFilledOut('shiptocity')) alert_text += "Please enter the ship to city\n"; if(!isFilledOut('shiptocountry')) alert_text += "Please enter the ship to country\n"; if(!isFilledOut('shiptopcode')) alert_text += "Please enter the ship to postal code\n"; @@ -112,6 +112,13 @@ function validateAndSubmit() { </tr> <tr class="even"> + <td><strong>Event Name: <span style="color: red;" title="Required">*</span></strong></td> + <td> + <input type="text" name="eventname" id="eventname" size="40"> + </td> +</tr> + +<tr class="odd"> <td><strong>Event Wiki Page: <span style="color: red;" title="Required">*</span></strong></td> <td> <input type="text" name="wikipage" id="wikipage" size="40"> @@ -121,7 +128,12 @@ function validateAndSubmit() { <tr class="even"> <td><strong>Estimated Attendance: <span style="color: red;" title="Required">*</span></strong></td> <td> - <input type="text" name="attendance" id="attendance" size="40"> + <select id="attendance" name="attendance"> + <option value="1-50">1-50</option> + <option value="51-200">51-200</option> + <option value="201-500">201-500</option> + <option value="501-1000+">501-1000+</option> + </select> </td> </tr @@ -137,12 +149,13 @@ function validateAndSubmit() { <tr class="odd"> <td><strong>Ship Before:</strong> <td> - <input type="text" id="shipdate" name="shipdate" size="10" - onchange="updateCalendarFromField(this)"> - <button type="button" class="calendar_button" id="button_calendar_date" - onclick="showCalendar('shipdate')"><span>Calendar</span> - </button> - <div id="con_calendar_shipdate"></div> + [% INCLUDE bug/field.html.tmpl + bug = default, + field = bug_fields.cf_due_date + value = default.cf_due_date, + editable = 1, + no_tds = 1 + %] </td> </tr> @@ -157,12 +170,12 @@ function validateAndSubmit() { </tr> <tr class="even"> - <td><strong>Address: <span style="color: red;" title="Required">*</span></strong></td> - <td><input name="shiptoaddress" id="shiptoaddress" placeholder="123 Main St." size="40"></td> + <td><strong>Address Line 1: <span style="color: red;" title="Required">*</span></strong></td> + <td><input name="shiptoaddress1" id="shiptoaddress1" placeholder="123 Main St." size="40"></td> </tr> <tr class="odd"> - <td><strong>Address 2:</strong></td> + <td><strong>Address Line 2:</strong></td> <td><input name="shiptoaddress2" id="shiptoaddress2" size="40"></td> </tr> @@ -172,7 +185,7 @@ function validateAndSubmit() { </tr> <tr class="odd"> - <td><strong>State:</strong></td> + <td><strong>State/Region (if applicable):</strong></td> <td><input name="shiptostate" id="shiptostate" placeholder="CA" size="40"></td> </tr> @@ -187,12 +200,12 @@ function validateAndSubmit() { </tr> <tr class="even"> - <td><strong>Contact Number: <span style="color: red;" title="Required">*</span></strong></td> + <td><strong>Phone (including country code): <span style="color: red;" title="Required">*</span></strong></td> <td><input name="shiptophone" id="shiptophone" placeholder="919-555-1212" size="40"></td> </tr> <tr class="odd"> - <td><strong>Personal ID/RUT:</strong><br><small>(if your country requires this)</small></td> + <td><strong>Custom Reference (Fiscal or VAT-number, if known):</strong><br><small>(if your country requires this)</small></td> <td><input name="shiptoidrut" id="shiptoidrut" size="40"></td> </tr> @@ -203,16 +216,16 @@ function validateAndSubmit() { </td> </tr> -<tr class="odd"> +<tr class="even"> <td><!--spacer--> </td> <td><!--spacer--> </td> </tr> -<tr class="even"> +<tr class="odd"> <td colspan="2"><strong>Swag Requested:</strong></td> </tr> -<tr class="odd"> +<tr class="even"> <td><strong>Stickers:</strong></td> <td><input type="checkbox" id="stickers" name="stickers" value="1"></td> </tr> @@ -285,8 +298,8 @@ function validateAndSubmit() { You will be notified by email of any progress made in resolving your request. </p> -<script type="text/javascript"> - createCalendar('shipdate'); -</script> +[% ELSE %] + <p>Sorry, you do not have access to this page.</p> +[% END %] [% PROCESS global/footer.html.tmpl %] diff --git a/extensions/REMO/template/en/default/bug/create/created-mozreps.html.tmpl b/extensions/REMO/template/en/default/bug/create/created-mozreps.html.tmpl new file mode 100644 index 000000000..378ab45d0 --- /dev/null +++ b/extensions/REMO/template/en/default/bug/create/created-mozreps.html.tmpl @@ -0,0 +1,38 @@ +[%# The contents of this file are subject to the Mozilla Public + # License Version 1.1 (the "License"); you may not use this file + # except in compliance with the License. You may obtain a copy of + # the License at http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS + # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + # implied. See the License for the specific language governing + # rights and limitations under the License. + # + # The Original Code is the REMO Bugzilla Extension. + # + # The Initial Developer of the Original Code is the Mozilla Foundation + # Portions created by the Initial Developers are Copyright (C) 2011 the + # Initial Developer. All Rights Reserved. + # + # Contributor(s): Byron Jones <glob@mozilla.com> + #%] + +[% PROCESS global/variables.none.tmpl %] + +[% PROCESS global/header.html.tmpl + title = "Mozilla Reps - Application Form" + +%] + +<h1>Thank you!</h1> + +<p> +Thank you for submitting your Mozilla Reps Application Form. A Mozilla Rep +mentor will contact you shortly at your bugzilla email address. +</p> + +<p style="font-size: x-small"> +Reference: <a href="show_bug.cgi?id=[% id %]">#[% id %]</a> +</p> + +[% PROCESS global/footer.html.tmpl %] diff --git a/extensions/REMO/template/en/default/hook/global/user-error-errors.html.tmpl b/extensions/REMO/template/en/default/hook/global/user-error-errors.html.tmpl new file mode 100644 index 000000000..200e678be --- /dev/null +++ b/extensions/REMO/template/en/default/hook/global/user-error-errors.html.tmpl @@ -0,0 +1,40 @@ +[%# The contents of this file are subject to the Mozilla Public + # License Version 1.1 (the "License"); you may not use this file + # except in compliance with the License. You may obtain a copy of + # the License at http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS + # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + # implied. See the License for the specific language governing + # rights and limitations under the License. + # + # The Original Code is the REMO Extension + # + # The Initial Developer of the Original Code is the Mozilla Foundation + # Portions created by the Initial Developers are Copyright (C) 2011 the + # Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Byron Jones <bjones@mozilla.com> + # David Lawrence <dkl@mozilla.com> + #%] + +[% IF error == "remo_payment_invalid_product" %] + [% title = "Mozilla Reps Payment Invalid Bug" %] + You can only attach budget payment information to [% terms.bugs %] under + the product 'Mozilla Reps' and component 'Budget Requests'. + +[% ELSIF error == "remo_payment_bug_edit_denied" %] + [% title = "Mozilla Reps Payment Bug Edit Denied" %] + You do not have permission to edit [% terms.bug %] '[% bug_id FILTER html %]'. + +[% ELSIF error == "remo_payment_cancel_dupe" %] + [% title = "Already filed payment request" %] + You already used the form to file + <a href="[% urlbase FILTER html %]attachment.cgi?id=[% attachid FILTER uri %]&action=edit"> + attachment [% attachid FILTER uri %]</a>.<br> + <br> + You can either <a href="[% urlbase FILTER html %]page.cgi?id=remo-form-payment.html"> + create a new payment request</a> or [% "go back to $terms.bug $bugid" FILTER bug_link(bugid) FILTER none %]. + +[% END %] diff --git a/extensions/BMO/template/en/default/pages/comment-remo-form-payment.txt.tmpl b/extensions/REMO/template/en/default/pages/comment-remo-form-payment.txt.tmpl index c43a92ae7..95c0af6e8 100644 --- a/extensions/BMO/template/en/default/pages/comment-remo-form-payment.txt.tmpl +++ b/extensions/REMO/template/en/default/pages/comment-remo-form-payment.txt.tmpl @@ -8,7 +8,7 @@ # implied. See the License for the specific language governing # rights and limitations under the License. # - # The Original Code is the BMO Extension + # The Original Code is the REMO Extension # # The Initial Developer of the Original Code is the Mozilla Foundation # Portions created by the Initial Developers are Copyright (C) 2011 the diff --git a/extensions/BMO/template/en/default/pages/remo-form-payment.html.tmpl b/extensions/REMO/template/en/default/pages/remo-form-payment.html.tmpl index ae4ca6f2e..0f5f206d3 100644 --- a/extensions/BMO/template/en/default/pages/remo-form-payment.html.tmpl +++ b/extensions/REMO/template/en/default/pages/remo-form-payment.html.tmpl @@ -8,7 +8,7 @@ # implied. See the License for the specific language governing # rights and limitations under the License. # - # The Original Code is the BMO Extension + # The Original Code is the REMO Extension # # The Initial Developer of the Original Code is the Mozilla Foundation # Portions created by the Initial Developers are Copyright (C) 2011 the @@ -22,8 +22,8 @@ [% PROCESS global/header.html.tmpl title = "Mozilla Reps Payment Form" - style_urls = [ 'extensions/BMO/web/styles/moz_reps.css' ] - javascript_urls = [ 'extensions/BMO/web/js/form_validate.js', + style_urls = [ 'extensions/REMO/web/styles/moz_reps.css' ] + javascript_urls = [ 'extensions/REMO/web/js/form_validate.js', 'js/util.js', 'js/field.js' ] yui = ['connection', 'json'] @@ -39,7 +39,7 @@ function validateAndSubmit() { if(!isFilledOut('lastname')) alert_text += "Please enter your last name\n"; if(!isFilledOut('wikiprofile')) alert_text += "Please enter a wiki user profile.\n"; if(!isFilledOut('wikipage')) alert_text += "Please enter a wiki page address.\n"; - if(!isFilledOut('bug_id')) alert_text += "Please enter a valid [%terms.bug %] id to attach this additional information to.\n"; + if(!isFilledOut('bug_id')) alert_text += "Please enter a valid [% terms.bug %] id to attach this additional information to.\n"; if(!isFilledOut('expenseform')) alert_text += "Please enter an expense form to upload.\n"; if(!isFilledOut('receipts')) alert_text += "Please enter a receipts file to upload.\n"; @@ -101,7 +101,7 @@ function getBugInfo (e, div) { "'Mozilla Reps' and component 'Budget Requests'."; } else { - bug_message = "Bug " + bug_id + " - " + data.result.bugs[0].status + + bug_message = "[% terms.Bug %] " + bug_id + " - " + data.result.bugs[0].status + " - " + data.result.bugs[0].summary; } } diff --git a/extensions/REMO/web/js/form_validate.js b/extensions/REMO/web/js/form_validate.js new file mode 100644 index 000000000..6c8fa6f07 --- /dev/null +++ b/extensions/REMO/web/js/form_validate.js @@ -0,0 +1,21 @@ +/** + * Some Form Validation and Interaction + **/ +//Makes sure that there is an '@' in the address with a '.' +//somewhere after it (and at least one character in between them + +function isValidEmail(email) { + var at_index = email.indexOf("@"); + var last_dot = email.lastIndexOf("."); + return at_index > 0 && last_dot > (at_index + 1); +} + +//Takes a DOM element id and makes sure that it is filled out +function isFilledOut(elem_id) { + var str = document.getElementById(elem_id).value; + return str.length>0 && str!="noneselected"; +} + +function isChecked(elem_id) { + return document.getElementById(elem_id).checked; +} diff --git a/extensions/REMO/web/js/swag.js b/extensions/REMO/web/js/swag.js new file mode 100644 index 000000000..47886b2a9 --- /dev/null +++ b/extensions/REMO/web/js/swag.js @@ -0,0 +1,60 @@ +/** + * Swag Request Form Functions + * Form Interal Swag Request Form + * dtran + * 7/6/09 + **/ + + +function evalToNumber(numberString) { + if(numberString=='') return 0; + return parseInt(numberString); +} + +function evalToNumberString(numberString) { + if(numberString=='') return '0'; + return numberString; +} +//item_array should be an array of DOM element ids +function getTotal(item_array) { + var total = 0; + for(var i in item_array) { + total += evalToNumber(document.getElementById(item_array[i]).value); + } + return total; +} + +function calculateTotalSwag() { + document.getElementById('Totalswag').value = + getTotal( new Array('Lanyards', + 'Stickers', + 'Bracelets', + 'Tattoos', + 'Buttons', + 'Posters')); + +} + + +function calculateTotalMensShirts() { + document.getElementById('mens_total').value = + getTotal( new Array('mens_s', + 'mens_m', + 'mens_l', + 'mens_xl', + 'mens_xxl', + 'mens_xxxl')); + +} + + +function calculateTotalWomensShirts() { + document.getElementById('womens_total').value = + getTotal( new Array('womens_s', + 'womens_m', + 'womens_l', + 'womens_xl', + 'womens_xxl', + 'womens_xxxl')); + +} diff --git a/extensions/BMO/web/styles/moz_reps.css b/extensions/REMO/web/styles/moz_reps.css index 989733c41..989733c41 100644 --- a/extensions/BMO/web/styles/moz_reps.css +++ b/extensions/REMO/web/styles/moz_reps.css diff --git a/extensions/SecureMail/template/en/default/account/prefs/securemail.html.tmpl b/extensions/SecureMail/template/en/default/account/prefs/securemail.html.tmpl index 2b643c961..dadfbb537 100644 --- a/extensions/SecureMail/template/en/default/account/prefs/securemail.html.tmpl +++ b/extensions/SecureMail/template/en/default/account/prefs/securemail.html.tmpl @@ -17,14 +17,12 @@ # Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org> #%] -<p>Some [% terms.bugs %] in this [% terms.Bugzilla %] are in groups the administrator has -deemed 'secure'. This means emails containing information about those [% terms.bugs %] +<p>Some bugs in this [% terms.Bugzilla %] are in groups the administrator has +deemed 'secure'. This means emails containing information about those bugs will only be sent encrypted. Enter your PGP/GPG public key or -SMIME certificate here to receive full update emails for such [% terms.bugs %].</p> +SMIME certificate here to receive full update emails for such bugs.</p> -<p>If you are a member of a secure group, or if you enter a key here, your password reset email -will also be sent to you encrypted. If you are a member of a secure group and do not enter a key, -you will not be able to reset your password without the assistance of an administrator.</p> +<p>If you are a member of a secure group, or if you enter a key here, your password reset email will also be sent to you encrypted. If you are a member of a secure group and do not enter a key, you will not be able to reset your password without the assistance of an administrator.</p> <p><a href="page.cgi?id=securemail/help.html">More help is available</a>.</p> diff --git a/extensions/SecureMail/template/en/default/pages/securemail/help.html.tmpl b/extensions/SecureMail/template/en/default/pages/securemail/help.html.tmpl index 4e1a5c577..76525eac2 100644 --- a/extensions/SecureMail/template/en/default/pages/securemail/help.html.tmpl +++ b/extensions/SecureMail/template/en/default/pages/securemail/help.html.tmpl @@ -24,12 +24,12 @@ title = "SecureMail Help" %] -[% terms.Bugzilla %] considers certain groups as "secure". If a [% terms.bug %] is in one of those groups, [% terms.Bugzilla %] -will not send unencrypted email about it. To receive encrypted email rather than just a "something changed" placeholder, you must provide either +Bugzilla considers certain groups as "secure". If a bug is in one of those groups, Bugzilla will not send unencrypted +email about it. To receive encrypted email rather than just a "something changed" placeholder, you must provide either a S/MIME or a GPG/PGP key on the <a href="[% urlbase FILTER none %]userprefs.cgi?tab=securemail">SecureMail preferences tab</a>.<br> <br> In addition, if you have uploaded a S/MIME or GPG/PGP key using the <a href="[% urlbase FILTER none %]userprefs.cgi?tab=securemail"> -SecureMail preferences tab</a>, if you request your password to be reset, [% terms.Bugzilla %] will send the reset email encrypted and you will +SecureMail preferences tab</a>, if you request your password to be reset, Bugzilla will send the reset email encrypted and you will be required to decrypt it to view the reset instructions. <h2>S/MIME</h2> @@ -86,7 +86,7 @@ You’ll have to answer several questions:</p> <p><code>gpg --armor --output pubkey.txt --export 'Your Name'</code></p> -<p>Paste the contents of pubkey.txt into the SecureMail text field in [% terms.Bugzilla %]. +<p>Paste the contents of pubkey.txt into the SecureMail text field in Bugzilla. <li>Configure your email client to use your associated private key to decrypt the encrypted emails. For Thunderbird, you need the <a href="https://addons.mozilla.org/en-us/thunderbird/addon/enigmail/">Enigmail</a> extension.</p> </ol> diff --git a/extensions/SiteMapIndex/Extension.pm b/extensions/SiteMapIndex/Extension.pm index f0b2a57d8..f36fa8c81 100644 --- a/extensions/SiteMapIndex/Extension.pm +++ b/extensions/SiteMapIndex/Extension.pm @@ -101,7 +101,8 @@ sub install_filesystem { | Bugzilla::Install::Filesystem::DIR_ALSO_WS_SERVE; $recurse_dirs->{$sitemap_path} = { - files => Bugzilla::Install::Filesystem::WS_SERVE, + files => Bugzilla::Install::Filesystem::CGI_WRITE + | Bugzilla::Install::Filesystem::DIR_ALSO_WS_SERVE, dirs => Bugzilla::Install::Filesystem::DIR_CGI_WRITE | Bugzilla::Install::Filesystem::DIR_ALSO_WS_SERVE }; diff --git a/extensions/SiteMapIndex/lib/Util.pm b/extensions/SiteMapIndex/lib/Util.pm index 3c322d8c7..6b5491d1c 100644 --- a/extensions/SiteMapIndex/lib/Util.pm +++ b/extensions/SiteMapIndex/lib/Util.pm @@ -112,8 +112,8 @@ sub generate_sitemap { last if !@$bugs; - # We only need the product links in the first sitemap file - $products = [] if $filecount > 1; + # We only need the product links in the first sitemap file + $products = [] if $filecount > 1; push(@$filelist, _generate_sitemap_file($extension_name, $filecount, $products, $bugs)); diff --git a/extensions/Splinter/lib/Util.pm b/extensions/Splinter/lib/Util.pm index c8c0d52d2..1861d7ab6 100644 --- a/extensions/Splinter/lib/Util.pm +++ b/extensions/Splinter/lib/Util.pm @@ -21,8 +21,6 @@ package Bugzilla::Extension::Splinter::Util; -use strict; - use Bugzilla; use Bugzilla::Util; @@ -68,9 +66,9 @@ sub get_review_url { my $bug_id = $bug->id; if (defined $absolute && $absolute) { - my $urlbase = correct_urlbase(); - $urlbase =~ s!/$!! if $base =~ "^/"; - $base = $urlbase . $base; + my $urlbase = correct_urlbase(); + $urlbase =~ s!/$!! if $base =~ "^/"; + $base = $urlbase . $base; } if ($base =~ /\?/) { @@ -95,12 +93,12 @@ sub munge_create_attachment { my ($bug, $intro_text, $attach_id, $view_link) = @_; if (attachment_id_is_patch ($attach_id)) { - return ("$intro_text" . + return ("$intro_text" . " View: $view_link\015\012" . " Review: " . get_review_url($bug, $attach_id, 1) . "\015\012"); } else { - return ("$intro_text --> ($view_link)"); + return ("$intro_text --> ($view_link)"); } } @@ -117,24 +115,24 @@ sub add_review_links_to_email { if ($email->header('Subject') =~ /^\[Bug\s+(\d+)\]/ && Bugzilla->user->can_see_bug($1)) { - $bug = Bugzilla::Bug->new($1); + $bug = Bugzilla::Bug->new($1); } return unless defined $bug; if ($body =~ /Review\s+of\s+attachment\s+\d+\s*:/) { - $body =~ s~(Review\s+of\s+attachment\s+(\d+)\s*:) + $body =~ s~(Review\s+of\s+attachment\s+(\d+)\s*:) ~"$1\015\012 --> (" . get_review_url($bug, $2, 1) . ")" ~egx; - $new_body = 1; + $new_body = 1; } if ($body =~ /Created attachment \d+\015\012 --> /) { - $body =~ s~(Created\ attachment\ (\d+)\015\012) + $body =~ s~(Created\ attachment\ (\d+)\015\012) \ -->\ \(([^\015\012]*)\)[^\015\012]* ~munge_create_attachment($bug, $1, $2, $3) ~egx; - $new_body = 1; + $new_body = 1; } $email->body_set($body) if $new_body; diff --git a/extensions/Splinter/template/en/default/pages/splinter.html.tmpl b/extensions/Splinter/template/en/default/pages/splinter.html.tmpl index a05cc87f9..4728967c7 100644 --- a/extensions/Splinter/template/en/default/pages/splinter.html.tmpl +++ b/extensions/Splinter/template/en/default/pages/splinter.html.tmpl @@ -16,7 +16,6 @@ # Red Hat, Inc. All Rights Reserved. # # Contributor(s): Owen Taylor <otaylor@redhat.com> - # David Lawrence <dkl@mozilla.com> #%] [% PROCESS global/header.html.tmpl @@ -27,7 +26,6 @@ "js/yui/assets/skins/sam/datatable.css", "extensions/Splinter/web/splinter.css" ] javascript_urls = [ "js/yui/element/element-min.js", - "js/yui/connection/connection-min.js", "js/yui/container/container-min.js", "js/yui/button/button-min.js", "js/yui/json/json-min.js", @@ -40,7 +38,7 @@ <script type="text/javascript"> Splinter.configBase = '[% urlbase FILTER none %][% Param('splinter_base') FILTER js %]'; - Splinter.configBugUrl = '[% urlbase FILTER none %]'; + Splinter.configBugzillaUrl = '[% urlbase FILTER none %]'; Splinter.configHaveExtension = true; Splinter.configHelp = '[% urlbase FILTER none %]page.cgi?id=splinter/help.html'; Splinter.configNote = ''; @@ -117,13 +115,14 @@ </div> <div id="bugInfo" style="display: none;"> - <b>[% terms.Bug %] <a id="bugLink"><span id="bugId"></span></a>:</b> + <b>Bug <a id="bugLink"><span id="bugId"></span></a>:</b> <span id="bugShortDesc"></span> - <span id="bugReporter"></span> - <span id="bugCreationDate"></span> </div> <div id="attachInfo" style="display:none;"> + <span id="attachObsolete"></span> <b>Attachment <a id="attachLink"><span id="attachId"></span></a>:</b> <span id="attachDesc"></span> - <span id="attachCreator"></span> - @@ -139,7 +138,7 @@ <div id="error" style="display: none;"> </div> <div id="enterBug" style="display: none;"> - [% terms.Bug %] to review: + Bug to review: <input id="enterBugInput" /> <input id="enterBugGo" type="button" value="Go" /> <div id="chooseReview" style="display: none;"> @@ -168,7 +167,7 @@ <li>To comment on a specific lines in the patch, first select the filename from the file navigation links.</li> <li>Then double click the line you want to review and a comment box will appear below the line.</li> <li>When the review is complete and you publish it, the overview comment and all line specific comments with their context, - will be combined together into a single review comment on the [% terms.bug %] report.</li> + will be combined together into a single review comment on the bug report.</li> <li>For more detailed instructions, read the Splinter <a id='helpLink' target='splinterHelp' href="[% urlbase FILTER none %]page.cgi?id=splinter/help.html">help page</a>. </li> @@ -234,7 +233,7 @@ </form> <div id="buttonBox"> <span id="attachmentStatusSpan">Patch Status: - <select id="attachmentStatus"> </select> + <select id="attachmentStatus"> </select> </span> <input id="publishButton" type="button" value="Publish" /> <input id="cancelButton" type="button" value="Cancel" /> diff --git a/extensions/Splinter/template/en/default/pages/splinter/help.html.tmpl b/extensions/Splinter/template/en/default/pages/splinter/help.html.tmpl index bff004c8f..7c797c94d 100644 --- a/extensions/Splinter/template/en/default/pages/splinter/help.html.tmpl +++ b/extensions/Splinter/template/en/default/pages/splinter/help.html.tmpl @@ -25,15 +25,15 @@ <h2>Splinter Patch Review</h2> <p> - Splinter is an add-on for [% terms.Bugzilla %] to allow conveniently + Splinter is an add-on for Bugzilla to allow conveniently reviewing patches that people have attached to - [% terms.Bugzilla %]. <a href="http://fishsoup.net/software/splinter">More + Bugzilla. <a href="http://fishsoup.net/software/splinter">More information about Splinter</a>. </p> <h3>The patch review view</h3> <p> If you get to Splinter by clicking on a link next to an - attachment in [% terms.Bugzilla %], you are presented with the patch + attachment in Bugzilla, you are presented with the patch review view. This view has a number of different pages that can be switched between with the links at the top of the screen. The first page is the Overview page, the other pages correspond to @@ -69,31 +69,31 @@ </p> <ul> <li> - An overall comment. The text area on the first page allows - you to enter your overall thoughts on the [% terms.bug %]. + An overall comment. The text area on the first page allows + you to enter your overall thoughts on the bug. </li> <li> - Detailed comments on changes within the files. To comment on a - line in a patch, double click on it, and a text area will open - beneath that comment. When you are done, click the Save button - to save your comment or the Cancel button to throw your - comment away. You can double-click on a saved comment to start - editing it again and make further changes. + Detailed comments on changes within the files. To comment on a + line in a patch, double click on it, and a text area will open + beneath that comment. When you are done, click the Save button + to save your comment or the Cancel button to throw your + comment away. You can double-click on a saved comment to start + editing it again and make further changes. </li> <li> - A change to the attachment status. (This is specific to - [% terms.Bugzilla %] instances that have attachment status, which is a - non-upstream patch. It's somewhat similar to attachment flags, - which splinter doesn't currently support displaying or - changing.) This allows you to mark a patch as read to commit - or needing additional work. This is done by changing the - drop-down next to the Publish button. + A change to the attachment status. (This is specific to + Bugzilla instances that have attachment status, which is a + non-upstream patch. It's somewhat similar to attachment flags, + which splinter doesn't currently support displaying or + changing.) This allows you to mark a patch as read to commit + or needing additional work. This is done by changing the + drop-down next to the Publish button. </li> </ul> <p> Once you are done writing your review, go back to Overview page and click the "Publish" button to submit it as a comment on the - [% terms.bug %]. The comment will have a link back to the review page so + bug. The comment will have a link back to the review page so that people can see your comments with the full context. </p> <h3>Saved drafts</h3> @@ -122,31 +122,31 @@ <h3>Uploading patches for review</h3> <p> Splinter doesn't really care how patches are provided to - [% terms.Bugzilla %], as long as they are well-formatted patches. If you are + Bugzilla, as long as they are well-formatted patches. If you are using Git for version control, you can either format changes as patches using <a href="http://www.kernel.org/pub/software/scm/git/docs/git-format-patch.html">'git - format-patch</a> and attach them manually to the [% terms.bug %], or you + format-patch</a> and attach them manually to the bug, or you can use <a href="http://fishsoup.net/software/git-bz">git-bz</a>. git-bz is highly recommended; it automates most of the steps - that Splinter can't handle: it files new [% terms.bugs %], attaches updated - attachments to existing [% terms.bugs %], and closes [% terms.bugs %] when you push the + that Splinter can't handle: it files new bugs, attaches updated + attachments to existing bugs, and closes bugs when you push the corresponding git commits to your central repository. </p> -<h3>The [% terms.bug %] review view</h3> +<h3>The bug review view</h3> <p> Splinter also has a view where it shows all patches attached to - the [% terms.bug %] with their status and links to review them. You are + the bug with their status and links to review them. You are taken to this page after publishing a review. You can also get - to this page with the [% terms.bug %] link in the upper-right corner of the + to this page with the bug link in the upper-right corner of the patch review view. </p> <h3>Your reviews</h3> <p> Splinter can also show you a list of all your draft and published reviews. Access this page with the "Your reviews" - link at the bottom of the [% terms.bug %] review view. In-progress drafts + link at the bottom of the bug review view. In-progress drafts are shown in bold. </p> diff --git a/extensions/Splinter/web/splinter.css b/extensions/Splinter/web/splinter.css index a4b4f0b6f..3f2eb84fe 100644 --- a/extensions/Splinter/web/splinter.css +++ b/extensions/Splinter/web/splinter.css @@ -34,6 +34,11 @@ textarea:focus { margin-bottom: 1em; } +#attachObsolete { + font-weight: bold; + color: #c00000; +} + .attachment-draft .attachment-id, .attachment-draft .attachment-desc { font-weight: bold; } @@ -400,3 +405,11 @@ div.review-patch-comment-text { padding-right: 5px; font-family: monospace; } + +.file-review-label { + font-size: 80%; +} + +.file-reviewed-nav { + text-decoration: line-through; +} diff --git a/extensions/Splinter/web/splinter.js b/extensions/Splinter/web/splinter.js index efcac8b6f..87a8b49d5 100644 --- a/extensions/Splinter/web/splinter.js +++ b/extensions/Splinter/web/splinter.js @@ -394,6 +394,7 @@ Splinter.Patch.File.prototype = { this.filename = filename; this.status = status; this.hunks = hunks; + this.fileReviewed = false; var l = 0; var i; @@ -1153,10 +1154,13 @@ Splinter.ReviewStorage.LocalReviewStorage.prototype = { } }, - saveDraft : function(bug, attachment, review) { + saveDraft : function(bug, attachment, review, extraProps) { var propertyName = this._reviewPropertyName(bug, attachment); - - this._updateOrCreateReviewInfo(bug, attachment, { isDraft: true }); + if (!extraProps) { + extraProps = {}; + } + extraProps.isDraft = true; + this._updateOrCreateReviewInfo(bug, attachment, extraProps); localStorage[propertyName] = "" + review; }, @@ -1313,6 +1317,12 @@ Splinter.haveDraft = function () { } } + for (i = 0; i < Splinter.thePatch.files.length; i++) { + if (Splinter.thePatch.files[i].fileReviewed) { + return true; + } + } + if (Splinter.flagChanged == 1) { return true; } @@ -1374,7 +1384,15 @@ Splinter.saveDraft = function () { var draftSaved = false; if (Splinter.haveDraft()) { - Splinter.reviewStorage.saveDraft(Splinter.theBug, Splinter.theAttachment, Splinter.theReview); + var filesReviewed = {}; + for (var i = 0; i < Splinter.thePatch.files.length; i++) { + var file = Splinter.thePatch.files[i]; + if (file.fileReviewed) { + filesReviewed[file.filename] = true; + } + } + Splinter.reviewStorage.saveDraft(Splinter.theBug, Splinter.theAttachment, Splinter.theReview, + { 'filesReviewed' : filesReviewed }); draftSaved = true; } else { Splinter.reviewStorage.deleteDraft(Splinter.theBug, Splinter.theAttachment, Splinter.theReview); @@ -1897,6 +1915,29 @@ Splinter.addPatchFile = function (file) { fileLabelStatus.appendChild(document.createTextNode(statusString)); fileLabelStatus.appendTo(fileLabel); + var fileReviewed = new Element(document.createElement('span')); + Dom.addClass(fileReviewed, 'file-review'); + Dom.setAttribute(fileReviewed, 'title', 'Indicates that a review has been completed for this file. ' + + 'This is for personal tracking purposes only and has no effect ' + + 'on the published review.'); + fileReviewed.appendTo(fileLabel); + + var fileReviewedInput = new Element(document.createElement('input')); + Dom.setAttribute(fileReviewedInput, 'type', 'checkbox'); + Dom.setAttribute(fileReviewedInput, 'id', 'file-review-checkbox-' + encodeURIComponent(file.filename)); + Dom.setAttribute(fileReviewedInput, 'onchange', "Splinter.toggleFileReviewed('" + + encodeURIComponent(file.filename) + "');"); + if (file.fileReviewed) { + Dom.setAttribute(fileReviewedInput, 'checked', 'true'); + } + fileReviewedInput.appendTo(fileReviewed); + + var fileReviewedLabel = new Element(document.createElement('label')); + Dom.addClass(fileReviewedLabel, 'file-review-label') + Dom.setAttribute(fileReviewedLabel, 'for', 'file-review-checkbox-' + encodeURIComponent(file.filename)); + fileReviewedLabel.appendChild(document.createTextNode(' Reviewed')); + fileReviewedLabel.appendTo(fileReviewed); + var lastHunk = file.hunks[file.hunks.length - 1]; var lastLine = Math.max(lastHunk.oldStart + lastHunk.oldCount - 1, lastHunk.newStart + lastHunk.newCount - 1); @@ -2079,7 +2120,7 @@ Splinter.toggleCollapsed = function (filename, display) { var i; for (i = 0; i < Splinter.thePatch.files.length; i++) { var file = Splinter.thePatch.files[i]; - if ((filename && file.filename == filename) || !filename) { + if (!filename || filename == file.filename) { var fileTableContainer = file.div.getElementsByClassName('file-table-container')[0]; var fileCollapseLink = file.div.getElementsByClassName('file-label-collapse')[0]; if (!display) { @@ -2091,6 +2132,31 @@ Splinter.toggleCollapsed = function (filename, display) { } } +Splinter.toggleFileReviewed = function (filename) { + var checkbox = Dom.get('file-review-checkbox-' + filename); + if (checkbox) { + filename = decodeURIComponent(filename); + for (var i = 0; i < Splinter.thePatch.files.length; i++) { + var file = Splinter.thePatch.files[i]; + if (file.filename == filename) { + file.fileReviewed = checkbox.checked; + + Splinter.saveDraft(); + Splinter.queueUpdateHaveDraft(); + + // Strike through file names to show review was completed + var fileNavLink = Dom.get('switch-' + encodeURIComponent(filename)); + if (file.fileReviewed) { + Dom.addClass(fileNavLink, 'file-reviewed-nav'); + } + else { + Dom.removeClass(fileNavLink, 'file-reviewed-nav'); + } + } + } + } +} + Splinter.showPatchFile = function (file) { Splinter.selectNavigationLink(file.filename); Dom.setStyle('overview', 'display', 'none'); @@ -2208,7 +2274,7 @@ Splinter.start = function () { } } - // We load the saved draft or create a new reeview *after* inserting the existing reviews + // We load the saved draft or create a new review *after* inserting the existing reviews // so that the ordering comes out right. if (Splinter.reviewStorage) { @@ -2221,6 +2287,18 @@ Splinter.start = function () { storedReviews[i].attachmentId == Splinter.theAttachment.id) { Dom.get("restoredLastModified").innerHTML = Splinter.Utils.formatDate(new Date(storedReviews[i].modificationTime)); + // Restore file reviewed checkboxes + if (storedReviews[i].filesReviewed) { + for (var j = 0; j < Splinter.thePatch.files.length; j++) { + var file = Splinter.thePatch.files[j]; + if (storedReviews[i].filesReviewed[file.filename]) { + file.fileReviewed = true; + // Strike through file names to show that review was completed + var fileNavLink = Dom.get('switch-' + encodeURIComponent(file.filename)); + Dom.addClass(fileNavLink, 'file-reviewed-nav'); + } + } + } } } } @@ -2434,7 +2512,7 @@ Splinter.init = function () { } Dom.get("bugId").innerHTML = Splinter.theBug.id; - Dom.get("bugLink").setAttribute('href', Splinter.configBugUrl + "show_bug.cgi?id=" + Splinter.theBug.id); + Dom.get("bugLink").setAttribute('href', Splinter.configBugzillaUrl + "show_bug.cgi?id=" + Splinter.theBug.id); Dom.get("bugShortDesc").innerHTML = YAHOO.lang.escapeHTML(Splinter.theBug.shortDesc); Dom.get("bugReporter").appendChild(document.createTextNode(Splinter.theBug.getReporter())); Dom.get("bugCreationDate").innerHTML = Splinter.Utils.formatDate(Splinter.theBug.creationDate); @@ -2457,11 +2535,14 @@ Splinter.init = function () { } else { Dom.get("attachId").innerHTML = Splinter.theAttachment.id; - Dom.get("attachLink").setAttribute('href', Splinter.configBugUrl + "attachment.cgi?id=" + Splinter.theAttachment.id); + Dom.get("attachLink").setAttribute('href', Splinter.configBugzillaUrl + "attachment.cgi?id=" + Splinter.theAttachment.id); Dom.get("attachDesc").innerHTML = YAHOO.lang.escapeHTML(Splinter.theAttachment.description); Dom.get("attachCreator").appendChild(document.createTextNode(Splinter.Bug._formatWho(Splinter.theAttachment.whoName, Splinter.theAttachment.whoEmail))); Dom.get("attachDate").innerHTML = Splinter.Utils.formatDate(Splinter.theAttachment.date); + if (Splinter.theAttachment.isObsolete) { + Dom.get("attachObsolete").innerHTML = 'OBSOLETE'; + } Dom.setStyle('attachInfo', 'display', 'block'); Dom.setStyle('quickHelpShow', 'display', 'block'); diff --git a/extensions/TagNewUsers/Extension.pm b/extensions/TagNewUsers/Extension.pm index 382a3c3d1..d71c4ea20 100644 --- a/extensions/TagNewUsers/Extension.pm +++ b/extensions/TagNewUsers/Extension.pm @@ -26,6 +26,7 @@ use Bugzilla::Field; use Bugzilla::User; use Bugzilla::Install::Util qw(indicate_progress); use Date::Parse; +use Scalar::Util qw(blessed); # users younger than PROFILE_AGE days will be tagged as new use constant PROFILE_AGE => 60; @@ -223,4 +224,19 @@ sub _user_is_new { || ($user->{creation_age} <= PROFILE_AGE); } +sub webservice_user_get { + my ($self, $args) = @_; + my ($webservice, $params, $users) = @$args{qw(webservice params users)}; + + foreach my $user (@$users) { + # Most of the time the hash values are XMLRPC::Data objects + my $email = blessed $user->{'email'} ? $user->{'email'}->value : $user->{'email'}; + if ($email) { + my $user_obj = Bugzilla::User->new({ name => $email }); + $user->{'is_new'} + = $webservice->type('boolean', $self->_user_is_new($user_obj) ? 1 : 0); + } + } +} + __PACKAGE__->NAME; diff --git a/extensions/TagNewUsers/template/en/default/hook/bug/comments-user.html.tmpl b/extensions/TagNewUsers/template/en/default/hook/bug/comments-user.html.tmpl index 316d381bb..274d26435 100644 --- a/extensions/TagNewUsers/template/en/default/hook/bug/comments-user.html.tmpl +++ b/extensions/TagNewUsers/template/en/default/hook/bug/comments-user.html.tmpl @@ -23,11 +23,11 @@ <span class="new_user" title=" -[%- comment.author.comment_count FILTER html %] comment[% "s" IF comment.author.comment_count != 1 -%] +[%- comment.author.comment_count %] comment[% "s" IF comment.author.comment_count != 1 -%] , created [% IF comment.author.creation_age == 0 %]today[% ELSIF comment.author.creation_age > 365 %]more than a year ago[% -ELSE %][% comment.author.creation_age FILTER html %] day[% "s" IF comment.author.creation_age != 1 %] ago[% END %]." +ELSE %][% comment.author.creation_age %] day[% "s" IF comment.author.creation_age != 1 %] ago[% END %]." > (New to [% terms.Bugzilla %]) </span> diff --git a/extensions/TypeSniffer/Extension.pm b/extensions/TypeSniffer/Extension.pm index ead4f40cf..fcd4f7dd6 100644 --- a/extensions/TypeSniffer/Extension.pm +++ b/extensions/TypeSniffer/Extension.pm @@ -42,28 +42,12 @@ sub attachment_process_data { if ($params->{'contenttypemethod'} eq 'autodetect' && $attributes->{'mimetype'} eq 'application/octet-stream') { - # data attribute can be either scalar data or filehandle - # bugzilla.org/docs/3.6/en/html/api/Bugzilla/Attachment.html#create - my $fh = $attributes->{'data'}; + # data is either a filehandle, or the data itself + my $fh = ${$args->{'data'}}; if (!ref($fh)) { - my $data = $attributes->{'data'}; - $fh = new IO::Scalar \$data; + $fh = IO::Scalar->new(\$fh); } - else { - # CGI.pm sends us an Fh that isn't actually an IO::Handle, but - # has a method for getting an actual handle out of it. - if (!$fh->isa('IO::Handle')) { - $fh = $fh->handle; - # ->handle returns an literal IO::Handle, even though the - # underlying object is a file. So we rebless it to be a proper - # IO::File object so that we can call ->seek on it and so on. - # Just in case CGI.pm fixes this some day, we check ->isa first. - if (!$fh->isa('IO::File')) { - bless $fh, 'IO::File'; - } - } - } - + my $mimetype = mimetype($fh); if ($mimetype) { $attributes->{'mimetype'} = $mimetype; diff --git a/extensions/Voting/Extension.pm b/extensions/Voting/Extension.pm index 6a90176ec..44344d7f5 100644 --- a/extensions/Voting/Extension.pm +++ b/extensions/Voting/Extension.pm @@ -48,24 +48,13 @@ use constant DEFAULT_VOTES_PER_BUG => 1; use constant CMT_POPULAR_VOTES => 3; use constant REL_VOTER => 4; -################ -# Installation # -################ - BEGIN { - *Bugzilla::Bug::votes = \&votes; + *Bugzilla::Bug::user_votes = \&_bug_user_votes; } -sub votes { - my $self = shift; - my $dbh = Bugzilla->dbh; - - return $self->{votes} if exists $self->{votes}; - - $self->{votes} = $dbh->selectrow_array('SELECT votes FROM bugs WHERE bug_id = ?', - undef, $self->id); - return $self->{votes}; -} +################ +# Installation # +################ sub db_schema_abstract_schema { my ($self, $args) = @_; @@ -123,6 +112,15 @@ sub install_update_db { # Objects # ########### +sub _bug_user_votes { + my ($self) = @_; + return $self->{'user_votes'} if exists $self->{'user_votes'}; + $self->{'user_votes'} = Bugzilla->dbh->selectrow_array( + "SELECT vote_count FROM votes WHERE bug_id = ? AND who = ?", + undef, $self->id, Bugzilla->user->id); + return $self->{'user_votes'}; +} + sub object_columns { my ($self, $args) = @_; my ($class, $columns) = @$args{qw(class columns)}; @@ -678,7 +676,7 @@ sub _modify_bug_votes { } } - $changes->{'_too_many_votes'} = \@toomanyvotes_list; + $changes->{'too_many_votes'} = \@toomanyvotes_list; # 2. too many total votes for a single user. # This part doesn't work in the general case because _remove_votes @@ -725,7 +723,7 @@ sub _modify_bug_votes { } } - $changes->{'_too_many_total_votes'} = \@toomanytotalvotes_list; + $changes->{'too_many_total_votes'} = \@toomanytotalvotes_list; # 3. enough votes to confirm my $bug_list = $dbh->selectcol_arrayref( @@ -738,7 +736,7 @@ sub _modify_bug_votes { my $confirmed = _confirm_if_vote_confirmed($bug_id); push (@updated_bugs, $bug_id) if $confirmed; } - $changes->{'_confirmed_bugs'} = \@updated_bugs; + $changes->{'confirmed_bugs'} = \@updated_bugs; # Now that changes are done, we can send emails to voters. foreach my $msg (@msgs) { @@ -748,7 +746,7 @@ sub _modify_bug_votes { foreach my $bug_id (@updated_bugs) { my $sent_bugmail = Bugzilla::BugMail::Send( $bug_id, { changer => Bugzilla->user }); - $changes->{'_confirmed_bugs_sent_bugmail'}->{$bug_id} = $sent_bugmail; + $changes->{'confirmed_bugs_sent_bugmail'}->{$bug_id} = $sent_bugmail; } } @@ -821,7 +819,7 @@ sub _remove_votes { }; my $voter = new Bugzilla::User($userid); - my $template = Bugzilla->template_inner($voter->setting('lang')); + my $template = Bugzilla->template_inner($voter->settings->{'lang'}->{'value'}); my $msg; $template->process("voting/votes-removed.txt.tmpl", $vars, \$msg); diff --git a/extensions/Voting/template/en/default/hook/admin/products/updated-changes.html.tmpl b/extensions/Voting/template/en/default/hook/admin/products/updated-changes.html.tmpl index 15fb1efe0..af2b1c102 100644 --- a/extensions/Voting/template/en/default/hook/admin/products/updated-changes.html.tmpl +++ b/extensions/Voting/template/en/default/hook/admin/products/updated-changes.html.tmpl @@ -56,8 +56,8 @@ <p>Checking existing votes in this product for anybody who now has too many votes for [% terms.abug %]...<br> - [% IF changes._too_many_votes.size %] - [% FOREACH detail = changes._too_many_votes %] + [% IF changes.too_many_votes.size %] + [% FOREACH detail = changes.too_many_votes %] →removed votes for [% terms.bug %] <a href="show_bug.cgi?id= [%- detail.id FILTER uri %]"> [%- detail.id FILTER html %]</a> from [% detail.name FILTER html %]<br> @@ -69,8 +69,8 @@ <p>Checking existing votes in this product for anybody who now has too many total votes...<br> - [% IF changes._too_many_total_votes.size %] - [% FOREACH detail = changes._too_many_total_votes %] + [% IF changes.too_many_total_votes.size %] + [% FOREACH detail = changes.too_many_total_votes %] →removed votes for [% terms.bug %] <a href="show_bug.cgi?id= [%- detail.id FILTER uri %]"> [%- detail.id FILTER html %]</a> from [% detail.name FILTER html %]<br> @@ -82,15 +82,15 @@ <p>Checking unconfirmed [% terms.bugs %] in this product for any which now have sufficient votes...<br> - [% IF changes._confirmed_bugs.size %] - [% FOREACH id = changes._confirmed_bugs %] + [% IF changes.confirmed_bugs.size %] + [% FOREACH id = changes.confirmed_bugs %] [%# This is INCLUDED instead of PROCESSED to avoid variables getting overwritten, which happens otherwise %] [% INCLUDE bug/process/results.html.tmpl type = 'votes' header_done = 1 - sent_bugmail = changes._confirmed_bugs_sent_bugmail.$id + sent_bugmail = changes.confirmed_bugs_sent_bugmail.$id id = id %] [% END %] diff --git a/extensions/Voting/template/en/default/hook/bug/edit-after_importance.html.tmpl b/extensions/Voting/template/en/default/hook/bug/edit-after_importance.html.tmpl index f73ffaebd..b57a5cb27 100644 --- a/extensions/Voting/template/en/default/hook/bug/edit-after_importance.html.tmpl +++ b/extensions/Voting/template/en/default/hook/bug/edit-after_importance.html.tmpl @@ -29,6 +29,9 @@ [% ELSE %] votes [% END %]</a> + [% IF bug.user_votes %] + including you + [% END %] [% END %] (<a href="page.cgi?id=voting/user.html&bug_id= [%- bug.id FILTER uri %]#vote_ diff --git a/extensions/Voting/template/en/default/pages/voting/user.html.tmpl b/extensions/Voting/template/en/default/pages/voting/user.html.tmpl index 61eaf8491..169e9995d 100644 --- a/extensions/Voting/template/en/default/pages/voting/user.html.tmpl +++ b/extensions/Voting/template/en/default/pages/voting/user.html.tmpl @@ -111,15 +111,8 @@ [% FOREACH bug = product.bugs %] <tr [% IF bug.id == this_bug.id && canedit %] class="bz_bug_being_voted_on" [% END %]> - <td> - [% IF bug.id == this_bug.id && canedit %] - [% IF product.onevoteonly %] - Vote For This [% terms.Bug %] → - [% ELSE %] - Enter Votes Here → - [% END %] - [%- END %] - </td> + <td>[% IF bug.id == this_bug.id && canedit %]Enter New Vote here → + [%- END %]</td> <td align="right"><a name="vote_[% bug.id FILTER html %]"> [% IF canedit %] [% IF product.onevoteonly %] diff --git a/js/comments.js b/js/comments.js index f46499b62..28ef54397 100644 --- a/js/comments.js +++ b/js/comments.js @@ -145,3 +145,30 @@ function goto_add_comments( anchor ){ },10); return false; } + +if (typeof Node == 'undefined') { + /* MSIE doesn't define Node, so provide a compatibility object */ + window.Node = { + TEXT_NODE: 3, + ENTITY_REFERENCE_NODE: 5 + }; +} + +/* Concatenates all text from element's childNodes. This is used + * instead of innerHTML because we want the actual text (and + * innerText is non-standard). + */ +function getText(element) { + var child, text = ""; + for (var i=0; i < element.childNodes.length; i++) { + child = element.childNodes[i]; + var type = child.nodeType; + if (type == Node.TEXT_NODE || type == Node.ENTITY_REFERENCE_NODE) { + text += child.nodeValue; + } else { + /* recurse into nodes of other types */ + text += getText(child); + } + } + return text; +} diff --git a/js/field.js b/js/field.js index 1a3bc3efd..a0684ffce 100644 --- a/js/field.js +++ b/js/field.js @@ -273,7 +273,7 @@ function showEditableField (e, ContainerInputArray) { * * var e: the event * var ContainerInputArray: An array containing the (edit) and text area and the input being displayed - * var ContainerInputArray[0]: the conainer that will be hidden usually shows the (edit) text + * var ContainerInputArray[0]: the container that will be hidden usually shows the (edit) text * var ContainerInputArray[1]: the input area and label that will be displayed * var ContainerInputArray[2]: the field that is on the page, might get changed by browser autocomplete * var ContainerInputArray[3]: the original value from the page loading. @@ -684,7 +684,8 @@ YAHOO.bugzilla.userAutocomplete = { id : YAHOO.bugzilla.userAutocomplete.counter, params : [ { match : [ decodeURIComponent(enteredText) ], - include_fields : [ "name", "real_name" ] + include_fields : [ "name", "real_name" ], + include_disabled : 1 } ] }; var stringified = YAHOO.lang.JSON.stringify(json_object); diff --git a/mod_perl.pl b/mod_perl.pl index 2f4016952..0a753078e 100644 --- a/mod_perl.pl +++ b/mod_perl.pl @@ -79,7 +79,7 @@ PerlChildInitHandler "sub { Bugzilla::RNG::srand(); srand(); }" PerlResponseHandler Bugzilla::ModPerl::ResponseHandler PerlCleanupHandler Apache2::SizeLimit Bugzilla::ModPerl::CleanupHandler PerlOptions +ParseHeaders - Options +ExecCGI + Options +ExecCGI +FollowSymLinks AllowOverride Limit FileInfo Indexes DirectoryIndex index.cgi index.html </Directory> diff --git a/post_bug.cgi b/post_bug.cgi index 6ca46fb3c..d4b679692 100755 --- a/post_bug.cgi +++ b/post_bug.cgi @@ -60,6 +60,12 @@ unless ($cgi->param()) { exit; } +# BMO: Don't allow updating of bugs if disabled +if (Bugzilla->params->{disable_bug_updates}) { + ThrowErrorPage('bug/process/updates-disabled.html.tmpl', + 'Bug updates are currently disabled.'); +} + # Detect if the user already used the same form to submit a bug my $token = trim($cgi->param('token')); if ($token) { diff --git a/process_bug.cgi b/process_bug.cgi index 382ee8b59..d44b9dda3 100755 --- a/process_bug.cgi +++ b/process_bug.cgi @@ -93,6 +93,12 @@ sub should_set { # Begin Data/Security Validation ###################################################################### +# BMO: Don't allow updating of bugs if disabled +if (Bugzilla->params->{disable_bug_updates}) { + ThrowErrorPage('bug/process/updates-disabled.html.tmpl', + 'Bug updates are currently disabled.'); +} + # Create a list of objects for all bugs being modified in this request. my @bug_objects; if (defined $cgi->param('id')) { @@ -78,6 +78,7 @@ if ($action eq "add") { check_hash_token($token, ['create-quips']); # Add the quip + # Upstreaming: https://bugzilla.mozilla.org/show_bug.cgi?id=621879 my $approved = (Bugzilla->params->{'quip_list_entry_control'} eq "open") || $user->in_group('bz_quip_moderators') || 0; my $comment = $cgi->param("quip"); diff --git a/request.cgi b/request.cgi index 16d7662e8..cac8ecc78 100755 --- a/request.cgi +++ b/request.cgi @@ -114,7 +114,8 @@ sub queue { flags.attach_id, attachments.description, requesters.realname, requesters.login_name, requestees.realname, requestees.login_name, COUNT(privs.group_id), - " . $dbh->sql_date_format('flags.modification_date', '%Y.%m.%d %H:%i') . + " . $dbh->sql_date_format('flags.modification_date', '%Y.%m.%d %H:%i') . ", + attachments.ispatch " . # Use the flags and flagtypes tables for information about the flags, # the bugs and attachments tables for target info, the profiles tables # for setter and requestee info, the products/components tables @@ -250,9 +251,9 @@ sub queue { products.name, components.name, flags.attach_id, attachments.description, requesters.realname, requesters.login_name, requestees.realname, - requestees.login_name, flags.modification_date, + requestees.login_name, flags.modification_date, attachments.ispatch cclist_accessible, bugs.reporter, bugs.reporter_accessible, - bugs.assigned_to'); + bugs.assigned_to, attachments.ispatch'); # Group the records, in other words order them by the group column # so the loop in the display template can break them up into separate @@ -295,7 +296,8 @@ sub queue { 'requester' => ($data[9] ? "$data[9] <$data[10]>" : $data[10]) , 'requestee' => ($data[11] ? "$data[11] <$data[12]>" : $data[12]) , 'restricted' => $data[13] ? 1 : 0, - 'created' => $data[14] + 'created' => $data[14], + 'ispatch' => $data[15], }; push(@requests, $request); } diff --git a/robots.txt b/robots.txt index 0f823cb24..6759c00b1 100644 --- a/robots.txt +++ b/robots.txt @@ -1,3 +1,12 @@ +User-agent: Browsershots +Disallow: + User-agent: * -Allow: /index.cgi -Disallow: / +Disallow: /*.cgi +Disallow: /*show_bug.cgi*ctype=* +Allow: / +Allow: /*index.cgi +Allow: /*page.cgi +Allow: /*show_bug.cgi +Allow: /*describecomponents.cgi +Sitemap: http://bugzilla.mozilla.org/page.cgi?id=sitemap/sitemap.xml diff --git a/skins/contrib/Dusk-Helvetica/buglist.css b/skins/contrib/Dusk-Helvetica/buglist.css new file mode 100644 index 000000000..2e14368b1 --- /dev/null +++ b/skins/contrib/Dusk-Helvetica/buglist.css @@ -0,0 +1,24 @@ +/* The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Bugzilla Bug Tracking System. + * + * The Initial Developer of the Original Code is Mike Schrag. + * Portions created by Marc Schumann are Copyright (c) 2007 Mike Schrag. + * All rights reserved. + * + * Contributor(s): Mike Schrag <mschrag@pobox.com> + * Byron Jones <bugzilla@glob.com.au> + * Marc Schumann <wurblzap@gmail.com> + */ + +tr.bz_bugitem:hover { + background-color: #ccccff; +} diff --git a/skins/contrib/Dusk-Helvetica/global.css b/skins/contrib/Dusk-Helvetica/global.css new file mode 100644 index 000000000..8478c1a88 --- /dev/null +++ b/skins/contrib/Dusk-Helvetica/global.css @@ -0,0 +1,263 @@ +/* The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Bugzilla Bug Tracking System. + * + * The Initial Developer of the Original Code is Mike Schrag. + * Portions created by Marc Schumann are Copyright (c) 2007 Mike Schrag. + * All rights reserved. + * + * Contributor(s): Mike Schrag <mschrag@pobox.com> + * Byron Jones <bugzilla@glob.com.au> + * Marc Schumann <wurblzap@gmail.com> + * Frédéric Buclin <LpSolit@gmail.com> + */ + +body { + background: #c8c8c8; + font-family: "Helvetica Neue", "Nimbus Sans L", Arial, sans-serif; + padding-left: 1em; + padding-right: 1em; +} + +body, td, th, input { + font-family: "Helvetica Neue", "Nimbus Sans L", Arial, sans-serif; +} + +/* page title */ + +#titles { + -moz-border-radius-topleft: 5px; + -moz-border-radius-topright: 5px; + border-top-left-radius: 5px; + border-top-right-radius: 5px; +} + +#header .links, #footer { + background-color: #929bb1; + color: #ddd; +} + +#header { + -moz-border-radius-bottomleft: 5px; + -moz-border-radius-bottomright: 5px; + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; + border: none; +} + +#header a, #footer a { + color: white; + text-decoration: none; +} +#header a:hover, #footer a:hover { + text-decoration: underline; +} + +/* body */ + +#bugzilla-body { + background: #f0f0f0; + color: black; + border: 1px solid #747e93; + padding: 10px; + font-size: 10pt; + -moz-border-radius: 5px; + border-radius: 5px; +} + +a { + color: #6070cf; +} +a:hover { + color: #8090ef; +} + +hr { + border-color: #969696; + border-style: dashed; + border-width: 1px; + margin-top: 10px; +} + +/* edit */ + +#bugzilla-body th { + font-weight: bold; + vertical-align: top; + white-space: nowrap; +} + +#bug-form td { + padding-top: 2px; +} + +/* attachments */ + +#attachment-list { + border: 2px solid #c8c8ba; + font-size: 9pt; +} + +#attachment-list th { + background-color: #e6e6d8; + border: none; + border-bottom: 1px solid #c8c8ba; + text-align: left; +} + +#attachment-list th a { + color: #646456; +} + +#attachment-list td { + border: none; +} + +#attachment-list-actions td { + border-top: 1px solid #c8c8ba; +} + +/************/ +/* Comments */ +/************/ + +#comments th { + font-size: 9pt; + font-weight: bold; + padding-top: 5px; + padding-right: 5px; + padding-bottom: 10px; + text-align: right; + vertical-align: top; + white-space: nowrap; +} + +#comments td { + padding-top: 2px; +} + +.reply-button a { + padding-left: 2px; + padding-right: 2px; +} + +.bz_comment { + background-color: #e8e8e8; + margin: 1px 1px 10px 1px; + border-width: 1px; + border-style: solid; + border-color: #c8c8ba; + padding: 5px; + font-size: 9pt; +} + +.bz_comment_head, .bz_first_comment_head { + margin: 0; padding: 0; + background-color: transparent; + font-weight: bold; +} + +.bz_comment_user { + margin-left: 0; +} + +.bz_comment.bz_private { + background-color: #f0e8e8; + border-color: #f8c8ba; +} + +.comment_rule { + display: none; +} + +/* footer */ + +#footer { + border: 1px solid #747e93; + width: 100%; + -moz-border-radius: 5px; + border-radius: 5px; +} + +#footer #links-actions, +#footer #links-edit, +#footer #links-saved, +#footer #links-special { + margin-top: 2ex; +} + +#footer .links { + border-spacing: 30px; + margin-bottom: 2ex; +} + +.separator { + color: #cccccc; +} + +/* tabs */ + +.tabbed .tabbody { + background: #f8f8f8; + padding: 1em; + border-style: solid; + border-color: #000000; + border-width: 0 3px 3px 1px; +} + +.tabs { + margin: 0; + padding: 0; + border-collapse: collapse; +} + +.tabs td { + background: #c8c8c8; + border-width: 1px; +} + +.tabs td.selected { + background: #f8f8f8; + border-width: 1px 3px 0 1px; +} + +.tabs td.spacer { + background: transparent; + border-top: none; + border-left: none; + border-right: none; +} + +/* other */ + +.bz_row_odd { + background-color: #f0f0f0; +} + +/* Rules specific for printing */ +@media print { + #header, + #footer, + .navigation { + display: none; + } + + body { + background-image: none; + background-color: #ffffff; + } + + #bugzilla-body { + border: none; + margin: 0; + padding: 0; + } +} diff --git a/skins/contrib/Dusk-Helvetica/index.css b/skins/contrib/Dusk-Helvetica/index.css new file mode 100644 index 000000000..c9c2d1705 --- /dev/null +++ b/skins/contrib/Dusk-Helvetica/index.css @@ -0,0 +1,9 @@ +/* + * Custom rules for index.css. + * The rules you put here override rules in that stylesheet. + */ + + div#page-index .outro + { + clear:both; + } diff --git a/skins/contrib/Dusk-Segoe/buglist.css b/skins/contrib/Dusk-Segoe/buglist.css new file mode 100644 index 000000000..2e14368b1 --- /dev/null +++ b/skins/contrib/Dusk-Segoe/buglist.css @@ -0,0 +1,24 @@ +/* The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Bugzilla Bug Tracking System. + * + * The Initial Developer of the Original Code is Mike Schrag. + * Portions created by Marc Schumann are Copyright (c) 2007 Mike Schrag. + * All rights reserved. + * + * Contributor(s): Mike Schrag <mschrag@pobox.com> + * Byron Jones <bugzilla@glob.com.au> + * Marc Schumann <wurblzap@gmail.com> + */ + +tr.bz_bugitem:hover { + background-color: #ccccff; +} diff --git a/skins/contrib/Dusk-Segoe/global.css b/skins/contrib/Dusk-Segoe/global.css new file mode 100644 index 000000000..f431aceba --- /dev/null +++ b/skins/contrib/Dusk-Segoe/global.css @@ -0,0 +1,263 @@ +/* The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Bugzilla Bug Tracking System. + * + * The Initial Developer of the Original Code is Mike Schrag. + * Portions created by Marc Schumann are Copyright (c) 2007 Mike Schrag. + * All rights reserved. + * + * Contributor(s): Mike Schrag <mschrag@pobox.com> + * Byron Jones <bugzilla@glob.com.au> + * Marc Schumann <wurblzap@gmail.com> + * Frédéric Buclin <LpSolit@gmail.com> + */ + +body { + background: #c8c8c8; + font-family: Segoe, "Segoe UI", "Helvetica Neue", Verdana, sans-serif; + padding-left: 1em; + padding-right: 1em; +} + +body, td, th, input { + font-family: Segoe, "Segoe UI", "Helvetica Neue", Verdana, sans-serif; +} + +/* page title */ + +#titles { + -moz-border-radius-topleft: 5px; + -moz-border-radius-topright: 5px; + border-top-left-radius: 5px; + border-top-right-radius: 5px; +} + +#header .links, #footer { + background-color: #929bb1; + color: #ddd; +} + +#header { + -moz-border-radius-bottomleft: 5px; + -moz-border-radius-bottomright: 5px; + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; + border: none; +} + +#header a, #footer a { + color: white; + text-decoration: none; +} +#header a:hover, #footer a:hover { + text-decoration: underline; +} + +/* body */ + +#bugzilla-body { + background: #f0f0f0; + color: black; + border: 1px solid #747e93; + padding: 10px; + font-size: 10pt; + -moz-border-radius: 5px; + border-radius: 5px; +} + +a { + color: #6070cf; +} +a:hover { + color: #8090ef; +} + +hr { + border-color: #969696; + border-style: dashed; + border-width: 1px; + margin-top: 10px; +} + +/* edit */ + +#bugzilla-body th { + font-weight: bold; + vertical-align: top; + white-space: nowrap; +} + +#bug-form td { + padding-top: 2px; +} + +/* attachments */ + +#attachment-list { + border: 2px solid #c8c8ba; + font-size: 9pt; +} + +#attachment-list th { + background-color: #e6e6d8; + border: none; + border-bottom: 1px solid #c8c8ba; + text-align: left; +} + +#attachment-list th a { + color: #646456; +} + +#attachment-list td { + border: none; +} + +#attachment-list-actions td { + border-top: 1px solid #c8c8ba; +} + +/************/ +/* Comments */ +/************/ + +#comments th { + font-size: 9pt; + font-weight: bold; + padding-top: 5px; + padding-right: 5px; + padding-bottom: 10px; + text-align: right; + vertical-align: top; + white-space: nowrap; +} + +#comments td { + padding-top: 2px; +} + +.reply-button a { + padding-left: 2px; + padding-right: 2px; +} + +.bz_comment { + background-color: #e8e8e8; + margin: 1px 1px 10px 1px; + border-width: 1px; + border-style: solid; + border-color: #c8c8ba; + padding: 5px; + font-size: 9pt; +} + +.bz_comment_head, .bz_first_comment_head { + margin: 0; padding: 0; + background-color: transparent; + font-weight: bold; +} + +.bz_comment_user { + margin-left: 0; +} + +.bz_comment.bz_private { + background-color: #f0e8e8; + border-color: #f8c8ba; +} + +.comment_rule { + display: none; +} + +/* footer */ + +#footer { + border: 1px solid #747e93; + width: 100%; + -moz-border-radius: 5px; + border-radius: 5px; +} + +#footer #links-actions, +#footer #links-edit, +#footer #links-saved, +#footer #links-special { + margin-top: 2ex; +} + +#footer .links { + border-spacing: 30px; + margin-bottom: 2ex; +} + +.separator { + color: #cccccc; +} + +/* tabs */ + +.tabbed .tabbody { + background: #f8f8f8; + padding: 1em; + border-style: solid; + border-color: #000000; + border-width: 0 3px 3px 1px; +} + +.tabs { + margin: 0; + padding: 0; + border-collapse: collapse; +} + +.tabs td { + background: #c8c8c8; + border-width: 1px; +} + +.tabs td.selected { + background: #f8f8f8; + border-width: 1px 3px 0 1px; +} + +.tabs td.spacer { + background: transparent; + border-top: none; + border-left: none; + border-right: none; +} + +/* other */ + +.bz_row_odd { + background-color: #f0f0f0; +} + +/* Rules specific for printing */ +@media print { + #header, + #footer, + .navigation { + display: none; + } + + body { + background-image: none; + background-color: #ffffff; + } + + #bugzilla-body { + border: none; + margin: 0; + padding: 0; + } +} diff --git a/skins/contrib/Dusk-Segoe/index.css b/skins/contrib/Dusk-Segoe/index.css new file mode 100644 index 000000000..c9c2d1705 --- /dev/null +++ b/skins/contrib/Dusk-Segoe/index.css @@ -0,0 +1,9 @@ +/* + * Custom rules for index.css. + * The rules you put here override rules in that stylesheet. + */ + + div#page-index .outro + { + clear:both; + } diff --git a/skins/contrib/Dusk-Segoe/show_bug.css b/skins/contrib/Dusk-Segoe/show_bug.css new file mode 100644 index 000000000..92e52d02e --- /dev/null +++ b/skins/contrib/Dusk-Segoe/show_bug.css @@ -0,0 +1,3 @@ +.bz_comment { + font-size: small; +} diff --git a/skins/contrib/Dusk/global.css b/skins/contrib/Dusk/global.css index 3a18e401e..e1f8afda1 100644 --- a/skins/contrib/Dusk/global.css +++ b/skins/contrib/Dusk/global.css @@ -22,11 +22,15 @@ body { background: #c8c8c8; - font-family: Helvetica, Arial, Geneva; + font-family: Verdana, sans-serif; padding-left: 1em; padding-right: 1em; } +body, td, th, input { + font-family: Verdana, sans-serif; +} + /* page title */ #titles { diff --git a/skins/custom/IE-fixes.css b/skins/custom/IE-fixes.css new file mode 100644 index 000000000..0d5c47630 --- /dev/null +++ b/skins/custom/IE-fixes.css @@ -0,0 +1,4 @@ +.bz_short_desc_column a, .bz_short_short_desc_column a { + /* color:inherit */ + color: expression(this.parentNode.currentStyle['color']); +} diff --git a/skins/custom/buglist.css b/skins/custom/buglist.css new file mode 100644 index 000000000..397bd95a4 --- /dev/null +++ b/skins/custom/buglist.css @@ -0,0 +1,36 @@ +/* For the JS-sorting buglist. */ + +th.sorttable_sorted, +th.sorttable_sorted_reverse, +th.sorted_0 { + background-color: #aaa; +} + +th.sorted_1 { + background-color: #bbb; +} + +th.sorted_2 { + background-color: #ccc; +} + +th.sorted_3 { + background-color: #ddd; +} + +th.sorted_4 { + background-color: #eee; +} + +th.sorted_5 { + background-color: #fff; +} + +.bz_short_desc_column a, .bz_short_short_desc_column a { + text-decoration: none; + color: inherit; +} + +.bz_short_desc_column a:hover, .bz_short_short_desc_column a:hover { + text-decoration: underline; +} diff --git a/skins/custom/global.css b/skins/custom/global.css new file mode 100644 index 000000000..3aee569f4 --- /dev/null +++ b/skins/custom/global.css @@ -0,0 +1,73 @@ +/* + * Custom rules for skins/standard/global.css. + * The rules you put here override rules in that stylesheet. + */ + +body { + margin: 0; + padding: 15px 15px 2px 15px; + background: none; +} + +#header { + margin-bottom: 0.5em; +} + +#header .links { + font-size: 90%; +} + +#header .btn, #header .txt { + font-size: 100%; +} + +#header #information { + color: #dddddd; + font-size: small; +} + +pre { + font-size: medium; +} + +.field_label { + text-align: left; +} + +#attachment_table { + width: 50em; +} + +#page-index #quicksearchForm { + padding-top: 20px; +} + +/* createaccount styling */ +.support_div { + width: 40%; + font-size: 80%; +} + +.support_div > img { + padding: 5px 20px; +} + +a { + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +a.controller { + font-size: 100%; + border: 1px solid #c0c0c0; + padding: 3px; +} + +#footer .outro { + text-align:left; + padding-left:1ex; + padding-bottom:1ex; +} diff --git a/skins/custom/index.css b/skins/custom/index.css new file mode 100644 index 000000000..3c1db9340 --- /dev/null +++ b/skins/custom/index.css @@ -0,0 +1,11 @@ +/* + * Custom rules for index.css. + * The rules you put here override rules in that stylesheet. + */ + +/* index.html.tmpl puts intro hook contents inside a div which causes + * * the icons to display over two rows when adding the Help icon. + * * So we change to inline to make it display a single row. */ +#page-index .intro { display: inline; } + +#get_help { background: url(../standard/index/help.png) no-repeat; } diff --git a/skins/custom/search_form.css b/skins/custom/search_form.css new file mode 100644 index 000000000..1855eb445 --- /dev/null +++ b/skins/custom/search_form.css @@ -0,0 +1,6 @@ + +/* let the browser choose the select height from the "size" param */ +.search_field_grid select { + height: auto; +} + diff --git a/skins/custom/show_bug.css b/skins/custom/show_bug.css new file mode 100644 index 000000000..6be078168 --- /dev/null +++ b/skins/custom/show_bug.css @@ -0,0 +1,85 @@ +/* + * Custom rules for show_bug.css. + * The rules you put here override rules in that stylesheet. + */ + +.last_comment_link { + float: right; + font-size: 80%; + font-weight: normal; + margin-left: 1em; +} + +/* colorize bugs in various groups */ +body[class*=bz_group_] { + background-color: #e0e0ff; + border-left: solid red 2px; + padding-left: 13px; +} + +body[class*=bz_group_] #bugzilla-body { + background-color: inherit; +} + +body.bz_group_webtools-security, +body.bz_group_websites-security, +body.bz_group_bugzilla-security { + background-color: #ffeeee; +} + +body.bz_group_client-services-security { + background-color: #ffff80; +} + +body.bz_group_core-security { + background-color: #ffe0b0; +} + +#legal_disclaimer { + width: 40em; + padding: 1em; + margin: 0 1em 1em 1em; + font-weight: bold; + border: 1px red solid; + background-color: lightyellow; +} + +.bz_patch { + background: #ffffcc; +} + +.cc_list_display { + list-style: none; + margin:0px; + padding:5px; + padding-right:20px; + height:100px; + overflow:auto; + float:left; + max-width:465px; + border:1px solid #CCC; +} + +.cc_list_display li { + margin:0px; + padding:0px; + white-space:nowrap; +} + +#wave_wand { + margin-top: 0px; +} + +/* put the width on the TD rather than the PRE to stop the col resizing + when comments are hidden */ +.bz_comment { + width: 55em; +} +.bz_comment_text { + width: auto; +} + +.bz_comment_number { + float: right; +} + diff --git a/skins/standard/enter_bug.css b/skins/standard/enter_bug.css index 88d9e9e85..34be42f7a 100644 --- a/skins/standard/enter_bug.css +++ b/skins/standard/enter_bug.css @@ -69,4 +69,4 @@ /* Make the Add Me to CC button never wrap. */ #possible_duplicates .yui-dt-col-update_token { white-space: nowrap; } -form#Create #possible_duplicates td { vertical-align: middle; }
\ No newline at end of file +form#Create #possible_duplicates td { vertical-align: middle; } diff --git a/skins/standard/guided.css b/skins/standard/guided.css new file mode 100644 index 000000000..efecfe3ce --- /dev/null +++ b/skins/standard/guided.css @@ -0,0 +1,4 @@ +#somebugs { + width: 100%; + height: 500px; +} diff --git a/template/en/default/account/auth/login-small.html.tmpl b/template/en/default/account/auth/login-small.html.tmpl index 39984aeaf..14efbc367 100644 --- a/template/en/default/account/auth/login-small.html.tmpl +++ b/template/en/default/account/auth/login-small.html.tmpl @@ -73,8 +73,8 @@ id="log_in[% qs_suffix %]"> <script type="text/javascript"> mini_login_constants = { - "login" : "login", - "warning" : "You must set the login and password before logging in." + "login" : "email address", + "warning" : "You must set the email address and password before logging in." }; [%# We need this event to fire after autocomplete, because it does # something different depending on whether or not there's already diff --git a/template/en/default/account/auth/login.html.tmpl b/template/en/default/account/auth/login.html.tmpl index 80dd12153..f11c33cdc 100644 --- a/template/en/default/account/auth/login.html.tmpl +++ b/template/en/default/account/auth/login.html.tmpl @@ -37,14 +37,14 @@ [% USE Bugzilla %] <p> - I need a legitimate login and password to continue. + I need an email address and password to continue. </p> <form name="login" action="[% target FILTER html %]" method="POST" [%- IF Bugzilla.cgi.param("data") %] enctype="multipart/form-data"[% END %]> <table> <tr> - <th align="right"><label for="Bugzilla_login">Login:</label></th> + <th align="right"><label for="Bugzilla_login">Email Address:</label></th> <td> <input size="35" id="Bugzilla_login" name="Bugzilla_login"> [% Param('emailsuffix') FILTER html %] @@ -64,7 +64,7 @@ <td> <input type="checkbox" id="Bugzilla_remember" name="Bugzilla_remember" value="on" [%+ "checked" IF Param('rememberlogin') == "defaulton" %]> - <label for="Bugzilla_remember">Remember my Login</label> + <label for="Bugzilla_remember">Remember my email address</label> </td> </tr> [% END %] @@ -110,7 +110,7 @@ <form id="forgot" method="get" action="token.cgi"> <input type="hidden" name="a" value="reqpw"> If you have an account, but have forgotten your password, - enter your login name below and submit a request + enter your email address below and submit a request to change your password.<br> <input size="35" name="loginname"> <input type="submit" id="request" value="Reset Password"> diff --git a/template/en/default/account/prefs/permissions.html.tmpl b/template/en/default/account/prefs/permissions.html.tmpl index 5e8dc9ca2..d3c787b07 100644 --- a/template/en/default/account/prefs/permissions.html.tmpl +++ b/template/en/default/account/prefs/permissions.html.tmpl @@ -65,9 +65,9 @@ There are no permission bits set on your account. [% END %] - [% IF user.in_group('editusers') %] + [% IF user.in_group('admin') %] <br> - You have editusers privileges. You can turn on and off + You have admin privileges. You can turn on and off all permissions for all users. [% ELSIF set_bits.size %] <br> diff --git a/template/en/default/admin/params/advanced.html.tmpl b/template/en/default/admin/params/advanced.html.tmpl index a8e8a297b..0ba40b375 100644 --- a/template/en/default/admin/params/advanced.html.tmpl +++ b/template/en/default/admin/params/advanced.html.tmpl @@ -78,4 +78,7 @@ _ " use the <code>http://user:pass@proxy_url/</code> syntax.", strict_transport_security => sts_desc, + + disable_bug_updates => + "When enabled, all updates to $terms.bugs will be blocked.", } %] diff --git a/template/en/default/attachment/createformcontents.html.tmpl b/template/en/default/attachment/createformcontents.html.tmpl index 5b04382b6..96ca587d2 100644 --- a/template/en/default/attachment/createformcontents.html.tmpl +++ b/template/en/default/attachment/createformcontents.html.tmpl @@ -54,6 +54,7 @@ <th>Content Type:</th> <td> <em>If the attachment is a patch, check the box below.</em><br> + [% Hook.process("patch_notes") %] <input type="checkbox" id="ispatch" name="ispatch" value="1" onchange="setContentTypeDisabledState(this.form);"> <label for="ispatch">patch</label><br><br> diff --git a/template/en/default/bug/comments.html.tmpl b/template/en/default/bug/comments.html.tmpl index 208ea092a..a6a2867bb 100644 --- a/template/en/default/bug/comments.html.tmpl +++ b/template/en/default/bug/comments.html.tmpl @@ -25,6 +25,37 @@ <script src="[% 'js/comments.js' FILTER mtime %]" type="text/javascript"> </script> +<script type="text/javascript"> +<!-- + /* Adds the reply text to the `comment' textarea */ + function replyToComment(id, real_id, name) { + var prefix = "(In reply to " + name + " from comment #" + id + ")\n"; + var replytext = ""; + [% IF user.settings.quote_replies.value == 'quoted_reply' %] + /* pre id="comment_name_N" */ + var text_elem = document.getElementById('comment_text_'+id); + var text = getText(text_elem); + replytext = prefix + wrapReplyText(text); + [% ELSIF user.settings.quote_replies.value == 'simple_reply' %] + replytext = prefix; + [% END %] + + [% IF user.is_insider %] + if (document.getElementById('isprivate_' + real_id).checked) { + document.getElementById('newcommentprivacy').checked = 'checked'; + updateCommentTagControl(document.getElementById('newcommentprivacy'), 'comment'); + } + [% END %] + + /* <textarea id="comment"> */ + var textarea = document.getElementById('comment'); + textarea.value += replytext; + + textarea.focus(); + } +//--> +</script> + [% DEFAULT start_at = 0 mode = "show" %] [% sort_order = user.settings.comment_sort_order.value %] @@ -52,6 +83,8 @@ [% END %] [% END %] +[% Hook.process("comment_banner") %] + <!-- This auto-sizes the comments and positions the collapse/expand links to the right. --> <table class="bz_comment_table" cellpadding="0" cellspacing="0"><tr> @@ -65,14 +98,6 @@ [% count = count + increment %] [% END %] -[% IF user.settings.comment_box_position.value == "before_comments" && user.id %] - <div class="bz_add_comment"> - <a href="#" - onclick="return goto_add_comments();"> - Add Comment</a> - </div> -[% END %] - [%# Note: this template is used in multiple places; if you use this hook, # make sure you are aware of this fact. #%] @@ -86,11 +111,6 @@ return false;">Collapse All Comments</a></li> <li><a href="#" onclick="toggle_all_comments('expand'); return false;">Expand All Comments</a></li> - [% IF user.settings.comment_box_position.value == "after_comments" && user.id %] - <li class="bz_add_comment"><a href="#" - onclick="return goto_add_comments('bug_status_bottom');"> - Add Comment</a></li> - [% END %] </ul> [% END %] </td> @@ -120,8 +140,12 @@ [% IF mode == "edit" %] <span class="bz_comment_actions"> + [<a class="bz_reply_link" href="#add_comment" + [% IF user.settings.quote_replies.value != 'off' %] + onclick="replyToComment('[% count %]', '[% comment.id %]', '[% comment.author.name || comment.author.nick FILTER html FILTER js %]'); return false;" + [% END %] + >reply</a>] <script type="text/javascript"><!-- - addReplyLink([% count %], [% comment.id %]); addCollapseLink([% count %]); // --> </script> </span> @@ -148,6 +172,7 @@ <span class="bz_comment_user"> [% INCLUDE global/user.html.tmpl who = comment.author %] + [% Hook.process('user', 'bug/comments.html.tmpl') %] </span> <span class="bz_comment_user_images"> diff --git a/template/en/default/bug/create/comment-guided.txt.tmpl b/template/en/default/bug/create/comment-guided.txt.tmpl index df04d8fb5..67748e594 100644 --- a/template/en/default/bug/create/comment-guided.txt.tmpl +++ b/template/en/default/bug/create/comment-guided.txt.tmpl @@ -41,7 +41,7 @@ Steps to Reproduce: [%+ cgi.param("reproduce_steps") %] [% END %] -[% IF cgi.param("actual_results") -%] +[% IF cgi.param("actual_results") %] Actual Results: [%+ cgi.param("actual_results") %] [% END %] diff --git a/template/en/default/bug/create/create-guided.html.tmpl b/template/en/default/bug/create/create-guided.html.tmpl index d10314628..43437bcd7 100644 --- a/template/en/default/bug/create/create-guided.html.tmpl +++ b/template/en/default/bug/create/create-guided.html.tmpl @@ -31,22 +31,12 @@ [% PROCESS global/header.html.tmpl title = "Enter $terms.ABug" onload = "PutDescription()" - style = "#somebugs { width: 100%; height: 500px }" + style_urls = [ "skins/standard/guided.css" ] %] [% style = "" %] -<p> - <font color="red"> - This is a template used on mozilla.org. This template, and the - comment-guided.txt.tmpl template that formats the data submitted via - the form in this template, are included as a demo of what it's - possible to do with custom templates in general, and custom [% terms.bug %] - entry templates in particular. As much of the text will not apply, - you should alter it - if you want to use this form on your [% terms.Bugzilla %] installation. - </font> -</p> +[% INCLUDE 'bug/create/user-message.html.tmpl' %] [% tablecolour = "#FFFFCC" %] @@ -80,15 +70,15 @@ function PutDescription() { [%# Include other products if sensible %] [% IF product.name == "Firefox" %] - [% productstring = "product=Mozilla%20Application%20Suite&product=Firefox" %] + [% productstring = "product=Toolkit&product=Core&product=Firefox" %] [% ELSIF product.name == "Thunderbird" %] - [% productstring = "product=Mozilla%20Application%20Suite&product=Thunderbird" %] + [% productstring = "product=MailNews%20Core&product=Thunderbird" %] [% ELSE %] [% productstring = BLOCK %]product=[% product.name FILTER uri %][% END %] [% END %] <p> - <a href="duplicates.cgi?[% productstring %]&format=simple" target="somebugs">All-time Top 100</a> (loaded initially) | + <a href="duplicates.cgi?[% productstring %]&format=simple" target="somebugs">All-time Top 20</a> (loaded initially) | <a href="duplicates.cgi?[% productstring %]&format=simple&sortby=delta&reverse=1&maxrows=100&changedsince=14" target="somebugs">Hot in the last two weeks</a> </p> @@ -112,14 +102,14 @@ function PutDescription() { <input type="hidden" name="product" value="[% product.name FILTER html %]"> [% IF product.name == "Firefox" OR product.name == "Thunderbird" OR - product.name == "Mozilla Application Suite" OR + product.name == "SeaMonkey" OR product.name == "Camino" %] <input type="hidden" name="product" value="Core"> <input type="hidden" name="product" value="Toolkit"> - <input type="hidden" name="product" value="PSM"> <input type="hidden" name="product" value="NSPR"> <input type="hidden" name="product" value="NSS"> - [% END %] + <input type="hidden" name="product" value="MailNews Core"> + [% END %] <input type="hidden" name="chfieldfrom" value="-6m"> <input type="hidden" name="chfieldto" value="Now"> <input type="hidden" name="chfield" value="[Bug creation]"> @@ -215,7 +205,7 @@ function PutDescription() { [%# We override rep_platform and op_sys for simplicity. The values chosen are based on which are most common in the b.m.o database %] - [% rep_platform = [ "PC", "Macintosh", "All", "Other" ] %] + [% rep_platform = [ "x86", "x86_64", "PowerPC", "All", "Other" ] %] <tr bgcolor="[% tablecolour %]"> <td align="right" valign="top"> @@ -238,7 +228,7 @@ function PutDescription() { </td> </tr> - [% IF product.name.match("Firefox|Camino|Mozilla Application Suite") %] + [% IF product.name.match("Firefox|Camino|SeaMonkey") %] [% matches = cgi.user_agent('Gecko/(\d+)') %] [% buildid = cgi.user_agent() IF matches %] [% END %] @@ -257,8 +247,8 @@ function PutDescription() { <p> This should identify the exact version of the product you were using. If the above field is blank or you know it is incorrect, copy the - version text from the product's Help | - About menu (for browsers this will begin with "Mozilla/5.0..."). + user agent text from the product's Help | Troubleshooting Information menu + (for browsers this will begin with "Mozilla/5.0..."). If the product won't start, instead paste the complete URL you downloaded it from. </p> @@ -275,7 +265,7 @@ function PutDescription() { URL that demonstrates the problem you are seeing (optional).<br> <b>IMPORTANT</b>: if the problem is with a broken web page, you need to report it - <a href="https://bugzilla.mozilla.org/page.cgi?id=broken-website.html">a different way</a>. + <a href="http://input.mozilla.com/feedback">a different way</a>. </p> </td> </tr> @@ -418,10 +408,7 @@ function PutDescription() { %] <p> Add any additional information you feel may be - relevant to this [% terms.bug %], such as the <b>theme</b> you were - using (does the [% terms.bug %] still occur - with the default theme?), a - <b><a href="http://kb.mozillazine.org/Quality_Feedback_Agent">Talkback crash ID</a></b>, or special + relevant to this [% terms.bug %], such as special information about <b>your computer's configuration</b>. Any information longer than a few lines, such as a <b>stack trace</b> or <b>HTML testcase</b>, should be added @@ -431,13 +418,12 @@ function PutDescription() { into your URL bar. <br> <br> - If you are reporting a crash, note the module in - which the software crashed (e.g., <tt>Application Violation in - gkhtml.dll</tt>). + If you are reporting a crash, please <a href="https://developer.mozilla.org/En/How_to_get_a_stacktrace_for_a_bug_report +">try and get a stack trace</a>, which tells us exactly where things went wrong. </p> </td> </tr> - + <tr> <td valign="top" align="right"> <b>Severity</b> diff --git a/template/en/default/bug/create/create.html.tmpl b/template/en/default/bug/create/create.html.tmpl index ee19ab5d6..52f4c3cf4 100644 --- a/template/en/default/bug/create/create.html.tmpl +++ b/template/en/default/bug/create/create.html.tmpl @@ -59,12 +59,10 @@ var flags = new Array([% product.components.size %]); comp_desc[[% count %]] = "[% c.description FILTER html_light FILTER js %]"; initialowners[[% count %]] = "[% c.default_assignee.login FILTER js %]"; [% flag_list = [] %] - [% FOREACH f = c.flag_types.bug %] - [% NEXT UNLESS f.is_active %] + [% FOREACH f = c.flag_types(is_active=>1).bug %] [% flag_list.push(f.id) %] [% END %] - [% FOREACH f = c.flag_types.attachment %] - [% NEXT UNLESS f.is_active %] + [% FOREACH f = c.flag_types(is_active=>1).attachment %] [% flag_list.push(f.id) %] [% END %] flags[[% count %]] = [[% flag_list.join(",") FILTER js %]]; @@ -358,18 +356,17 @@ TUI_hide_default('attachment_text_field'); %] <td rowspan="[% num_rows FILTER html %]"> - [% IF product.flag_types.bug.size > 0 %] + [% IF product.flag_types(isactive=>1).bug.size > 0 %] [% display_flag_headers = 0 %] [% any_flags_requesteeble = 0 %] - [% FOREACH flag_type = product.flag_types.bug %] - [% NEXT UNLESS flag_type.is_active %] + [% FOREACH flag_type = product.flag_types(is_active=>1).bug %] [% display_flag_headers = 1 %] [% SET any_flags_requesteeble = 1 IF flag_type.is_requestable && flag_type.is_requesteeble %] [% END %] [% IF display_flag_headers %] - [% PROCESS "flag/list.html.tmpl" flag_types = product.flag_types.bug + [% PROCESS "flag/list.html.tmpl" flag_types = product.flag_types(is_active=>1).bug any_flags_requesteeble = any_flags_requesteeble flag_table_id = "bug_flags" %] @@ -488,9 +485,11 @@ TUI_hide_default('attachment_text_field'); <tbody> [% USE Bugzilla %] - + [% FOREACH field = Bugzilla.active_custom_fields %] [% NEXT UNLESS field.enter_bug %] + [% NEXT IF cf_hidden_in_product(field.name, product.name, component.name) %] + [% SET value = ${field.name}.defined ? ${field.name} : "" %] <tr [% 'class="expert_fields"' IF !field.is_mandatory %]> [% INCLUDE bug/field.html.tmpl @@ -574,22 +573,6 @@ TUI_hide_default('attachment_text_field'); </td> </tr> - [% IF user.is_insider %] - <tr class="expert_fields"> - <th> </th> - <td colspan="3"> - - <input type="checkbox" id="comment_is_private" name="comment_is_private" - [% ' checked="checked"' IF comment_is_private %] - onClick="updateCommentTagControl(this, 'comment')"> - <label for="comment_is_private"> - Make description and any new attachment private (visible only to members - of the <strong>[% Param('insidergroup') FILTER html %]</strong> group) - </label> - </td> - </tr> - [% END %] - [% IF Param("maxattachmentsize") %] <tr> <th>Attachment:</th> @@ -605,10 +588,20 @@ TUI_hide_default('attachment_text_field'); <legend>Add an attachment</legend> <table class="attachment_entry"> [% PROCESS attachment/createformcontents.html.tmpl - flag_types = product.flag_types.attachment + flag_types = product.flag_types(is_active=>1).attachment any_flags_requesteeble = 1 flag_table_id ="attachment_flags" %] </table> + + [% IF user.is_insider %] + <input type="checkbox" id="comment_is_private" name="comment_is_private" + [% ' checked="checked"' IF comment_is_private %] + onClick="updateCommentTagControl(this, 'comment')"> + <label for="comment_is_private"> + Make this attachment and [% terms.bug %] description private (visible only + to members of the <strong>[% Param('insidergroup') FILTER html %]</strong> group) + </label> + [% END %] </fieldset> </div> </td> @@ -629,6 +622,13 @@ TUI_hide_default('attachment_text_field'); [% END %] <tr> + <th>Status Whiteboard:</th> + <td colspan="3"> + <input id="status_whiteboard" name="status_whiteboard" size="70" + value="[% status_whiteboard FILTER html %]"> + </td> + </tr> + <tr> [% INCLUDE "bug/field-label.html.tmpl" field = bug_fields.dependson editable = 1 %] diff --git a/template/en/default/bug/edit.html.tmpl b/template/en/default/bug/edit.html.tmpl index ab150dd31..b44d7c9b0 100644 --- a/template/en/default/bug/edit.html.tmpl +++ b/template/en/default/bug/edit.html.tmpl @@ -32,21 +32,13 @@ <script type="text/javascript"> <!-- - - /* Outputs a link to call replyToComment(); used to reduce HTML output */ - function addReplyLink(id, real_id) { - /* XXX this should really be updated to use the DOM Core's - * createElement, but finding a container isn't trivial. - */ - [% IF user.settings.quote_replies.value != 'off' %] - document.write('[<a href="#add_comment" onclick="replyToComment(' + - id + ',' + real_id + '); return false;">reply<' + '/a>]'); - [% END %] - } - /* Adds the reply text to the `comment' textarea */ - function replyToComment(id, real_id) { - var prefix = "(In reply to comment #" + id + ")\n"; + function replyToComment(id, real_id, name) { + var prefix = "(In reply to "; + if (name) { + prefix = prefix + name + " from"; + } + prefix = prefix + " comment #" + id + ")\n"; var replytext = ""; [% IF user.settings.quote_replies.value == 'quoted_reply' %] /* pre id="comment_name_N" */ @@ -57,12 +49,15 @@ replytext = prefix; [% END %] - [% IF user.is_insider %] - if (document.getElementById('isprivate_' + real_id).checked) { - document.getElementById('newcommentprivacy').checked = 'checked'; - updateCommentTagControl(document.getElementById('newcommentprivacy'), 'comment'); - } - [% END %] + [% IF user.is_insider %] + if (document.getElementById('isprivate_' + real_id).checked) { + document.getElementById('newcommentprivacy').checked = 'checked'; + updateCommentTagControl(document.getElementById('newcommentprivacy'), 'comment'); + } + [% END %] + + /* Remove embedded links to attachment details */ + replytext = replytext.replace(/(attachment\s+\d+)(\s+\[[^\[]+\])+/gi, '$1'); /* <textarea id="comment"> */ var textarea = document.getElementById('comment'); @@ -71,33 +66,6 @@ textarea.focus(); } - if (typeof Node == 'undefined') { - /* MSIE doesn't define Node, so provide a compatibility object */ - window.Node = { - TEXT_NODE: 3, - ENTITY_REFERENCE_NODE: 5 - }; - } - - /* Concatenates all text from element's childNodes. This is used - * instead of innerHTML because we want the actual text (and - * innerText is non-standard). - */ - function getText(element) { - var child, text = ""; - for (var i=0; i < element.childNodes.length; i++) { - child = element.childNodes[i]; - var type = child.nodeType; - if (type == Node.TEXT_NODE || type == Node.ENTITY_REFERENCE_NODE) { - text += child.nodeValue; - } else { - /* recurse into nodes of other types */ - text += getText(child); - } - } - return text; - } - [% IF user.is_timetracker %] var fRemainingTime = [% bug.remaining_time %]; // holds the original value function adjustRemainingTime() { @@ -116,7 +84,6 @@ // if the remaining time is changed manually, update fRemainingTime fRemainingTime = document.changeform.remaining_time.value; } - [% END %] /* Index all classifications so we can keep track of the classification @@ -164,17 +131,26 @@ [% PROCESS section_url_keyword_whiteboard %] [% PROCESS section_spacer %] - - [%# *** Dependencies *** %] + + [%# *** Dependencies and duplicates *** %] + [% PROCESS section_duplicates %] + [% PROCESS section_dependson_blocks %] - + + [% IF user.id %] + <tr> + <td colspan="2"> + [% PROCESS commit_button id="_top"%] + </td> + </tr> + [% END %] </table> </td> <td> <div class="bz_column_spacer"> </div> </td> [%# 2nd Column %] - <td id="bz_show_bug_column_2" class="bz_show_bug_column"> + <td id="bz_show_bug_column_2" class="bz_show_bug_column_table" valign="top"> <table cellpadding="3" cellspacing="1"> [%# *** Reported and modified dates *** %] [% PROCESS section_dates %] @@ -182,16 +158,16 @@ [% PROCESS section_cclist %] [% PROCESS section_spacer %] - - [% PROCESS section_see_also %] + + [% PROCESS section_flags %] - [% PROCESS section_customfields %] + [% PROCESS section_see_also %] [% PROCESS section_spacer %] + [% PROCESS section_customfields %] + [% Hook.process("after_custom_fields") %] - - [% PROCESS section_flags %] </table> </td> @@ -220,6 +196,8 @@ [% IF user.settings.comment_box_position.value == 'before_comments' %] [% PROCESS comment_box %] + [% ELSE %] + [% PROCESS summon_comment_box %] [% END %] </td> <td> @@ -238,7 +216,10 @@ [% IF user.settings.comment_box_position.value == 'after_comments' %] <hr> [% PROCESS comment_box %] - [% END %] + [% ELSE %] + [% PROCESS summon_comment_box %] + [% END %] + </form> @@ -249,7 +230,10 @@ [% BLOCK section_title %] [%# That's the main table, which contains all editable fields. %] <div class="bz_alias_short_desc_container edit_form"> - [% PROCESS commit_button id="_top"%] + <span class="last_comment_link"> + <a href="#c[% bug.comments.size - 1 %]" + accesskey="l"><b>L</b>ast Comment</a> + </span> <a href="show_bug.cgi?id=[% bug.bug_id %]"> [%-# %]<b>[% terms.Bug %] [% bug.bug_id FILTER html %]</b> [%-# %]</a> -<span id="summary_alias_container" class="bz_default_hidden"> @@ -408,6 +392,30 @@ </span> </td> </tr> + [% IF Param('usestatuswhiteboard') %] + <tr> + <td class="field_label"> + <label for="status_whiteboard" accesskey="w"><b><u>W</u>hiteboard</b></label>: + </td> + [% PROCESS input inputname => "status_whiteboard" size => "40" colspan => 2 %] + </tr> + [% END %] + + [% IF use_keywords %] + <tr> + <td class="field_label"> + <label for="keywords" accesskey="k"> + <b><a href="describekeywords.cgi"><u>K</u>eywords</a></b></label>: + </td> + <td class="field_value" colspan="2"> + [% INCLUDE bug/field.html.tmpl + bug = bug, field = bug_fields.keywords, value = bug.keywords + editable = bug.check_can_change_field("keywords", 0, 1), + no_tds = 1 + %] + </td> + </tr> + [% END %] [% END %] [%############################################################################%] @@ -568,14 +576,17 @@ <td> [% IF bug.check_can_change_field("bug_file_loc", 0, 1) %] <span id="bz_url_edit_container" class="bz_default_hidden"> - [% IF is_safe_url(bug.bug_file_loc) %] - <a href="[% bug.bug_file_loc FILTER html %]" target="_blank" - title="[% bug.bug_file_loc FILTER html %]"> - [% bug.bug_file_loc FILTER truncate(40) FILTER html %]</a> - [% ELSE %] - [% bug.bug_file_loc FILTER html %] - [% END %] - (<a href="#" id="bz_url_edit_action">edit</a>)</span> + <a href="[% bug.bug_file_loc FILTER html %]" target="_blank" + title="[% bug.bug_file_loc FILTER html %]" + [% IF NOT is_safe_url(bug.bug_file_loc) %] + onclick="return confirm( + 'This is considered an unsafe URL and could possibly be harmful. ' + + 'The full URL is:\n\n[% bug.bug_file_loc FILTER js FILTER html %]\n\n' + + 'Continue?')" + [% END %]> + [% bug.bug_file_loc FILTER truncate(40) FILTER html %]</a> + (<a href="#" id="bz_url_edit_action">edit</a>) + </span> [% END %] <span id="bz_url_input_area"> [% url_output = PROCESS input no_td=1 inputname => "bug_file_loc" size => "40" colspan => 2 %] @@ -597,36 +608,34 @@ [% END %] </td> </tr> - - [% IF Param('usestatuswhiteboard') %] - <tr> - <td class="field_label"> - <label for="status_whiteboard" accesskey="w"><b><u>W</u>hiteboard</b></label>: - </td> - [% PROCESS input inputname => "status_whiteboard" size => "40" colspan => 2 %] - </tr> - [% END %] - - [% IF use_keywords %] - <tr> - <td class="field_label"> - <label for="keywords" accesskey="k"> - <b><a href="describekeywords.cgi"><u>K</u>eywords</a></b></label>: - </td> - <td class="field_value" colspan="2"> - [% INCLUDE bug/field.html.tmpl - bug = bug, field = bug_fields.keywords, value = bug.keywords - editable = bug.check_can_change_field("keywords", 0, 1), - no_tds = 1 - %] - </td> - </tr> - [% END %] [% END %] [%############################################################################%] -[%# Block for Depends On / Blocks #%] +[%# Block for Duplicates #%] [%############################################################################%] + +[% BLOCK section_duplicates %] + [% RETURN UNLESS bug.duplicates.size %] + <tr> + <td class="field_label"> + <label for="duplicates">Duplicates</label>: + </td> + <td class="field_value" colspan="2"> + <span id="duplicates"> + [% FOREACH dupe = bug.duplicates %] + [% dupe.id FILTER bug_link(dupe, use_alias => 1) FILTER none %][% " " %] + [% END %] + </span> + (<a href="buglist.cgi?bug_id=[% bug.duplicate_ids.join(",") FILTER html %]"> + [%-%]view as [% terms.bug %] list</a>) + </td> + </tr> +[% END %] + +[%############################################################################%] +[%# Block for Depends On / Blocks #%] +[%############################################################################%] + [% BLOCK section_dependson_blocks %] <tr> [% INCLUDE dependencies @@ -812,10 +821,18 @@ [% IF user.id || bug.cc.size %] <span id="cc_edit_area_showhide_container" class="bz_default_hidden"> (<a href="#" id="cc_edit_area_showhide">[% IF user.id %]edit[% ELSE %]show[% END %]</a>) - </span> + [% IF user.id %] + <div id="cc_list_num_users"> + <ul class="cc_list_display"> + [% FOREACH c = bug.cc %] + <li>[% c FILTER email FILTER html %]</li> + [% END %] + </ul> + </div> + [% END %] + </span> [% END %] <div id="cc_edit_area"> - <br> [% IF user.id %] <div> <div><label for="cc"><b>Add</b></label></div> @@ -922,6 +939,8 @@ [%# *** Custom Fields *** %] [% USE Bugzilla %] [% FOREACH field = Bugzilla.active_custom_fields %] + [% NEXT IF NOT user.id AND field.value == "---" %] + [% NEXT IF cf_hidden_in_product(field.name, bug.product, bug.component, 1) %] <tr> [% PROCESS bug/field.html.tmpl value = bug.${field.name} editable = bug.check_can_change_field(field.name, 0, 1) @@ -1127,6 +1146,21 @@ </div> [% END %] +[% BLOCK summon_comment_box %] +<div id="comment_top_hat"> + <script type="text/javascript"> + function summonCommentBox() { + var commentbox = document.getElementById('add_comment'); + document.getElementById('comment_top_hat').appendChild(commentbox); + document.getElementById('wave_wand').style.display = 'none'; + } + </script> + <p id="wave_wand"> + <a href="javascript:summonCommentBox()"><i>Summon comment box</i></a> + </p> +</div> +[% END %] + [%############################################################################%] [%# Block for SELECT fields #%] [%############################################################################%] diff --git a/template/en/default/bug/field.html.tmpl b/template/en/default/bug/field.html.tmpl index 323b4b6be..bb9c553e5 100644 --- a/template/en/default/bug/field.html.tmpl +++ b/template/en/default/bug/field.html.tmpl @@ -125,6 +125,30 @@ [% END %] [% FOREACH legal_value = legal_values %] [% NEXT IF NOT legal_value.is_active AND NOT value.contains(legal_value.name).size %] + + [%# Purpose: hide field values from those who can't change them %] + [% IF field.name.match("^cf_blocking_") OR + field.name.match("^cf_status_") OR + field.name.match("^cf_tracking_") OR + field.name == "resolution" %] + [% NEXT UNLESS bug.check_can_change_field(field.name, '---', legal_value.name) OR + value.contains(legal_value.name).size %] + [% END %] + + [% IF field.name == "resolution" && + legal_value.name != bug.resolution %] + [% r = legal_value.name %] + [% IF bug.user.canconfirm && + !(bug.user.canedit || bug.user.isreporter) %] + [% NEXT IF r != "WORKSFORME" && r != "INCOMPLETE" %] + [% END %] + [% IF bug.user.isreporter && + !(bug.user.canconfirm || bug.user.canedit) %] + [% NEXT IF r == "INCOMPLETE" %] + [% END %] + [% NEXT IF r == "EXPIRED" %] + [% END %] + <option value="[% legal_value.name FILTER html %]" id="v[% legal_value.id FILTER html %]_ [%- field.name FILTER html %]" diff --git a/template/en/default/bug/process/updates-disabled.html.tmpl b/template/en/default/bug/process/updates-disabled.html.tmpl new file mode 100644 index 000000000..5ea84d476 --- /dev/null +++ b/template/en/default/bug/process/updates-disabled.html.tmpl @@ -0,0 +1,73 @@ +[%# The contents of this file are subject to the Mozilla Public License Version + # 1.1 (the "License"); you may not use this file except in compliance with + # the License. You may obtain a copy of the License at + # http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS IS" basis, + # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + # for the specific language governing rights and limitations under the + # License. + # + # The Original Code is the Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is + # the Mozilla Foundation. + # Portions created by the Initial Developer are Copyright (C) 2011 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): Byron Jones <glob@mozilla.com> + # + #%] +[% PROCESS global/variables.none.tmpl %] +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> +<html> +<head> +<title>[% terms.Bugzilla %] - [% terms.Bug %] Updates Temporarily Suspended</title> +<style type="text/css"> +body { + margin: 2em; + background-color: #455372; + color: #fff; + font-family: verdana, sans-serif; + font-size: small; +} +a { + color: #fff; + text-decoration: underline; +} +#buggie { + float: left; +} +#content { + margin-left: 100px; + max-width: 600px; +} +</style> +</head> +<body> +<img src="images/buggie.png" id="buggie" alt="buggie"> +<div id="content"> +<h1>[% terms.Bug %] Updates Temporarily Suspended</h1> + +<p> +We are currently adding a field to [% terms.Bugzilla %]. This requires us to +prevent updates to [% terms.bugs %] for the duration of the database schema +change to add the field (usually 3 to 5 minutes). +</p> + +<p> +<b>You should be able to leave this page open, wait a minute or two, then hit +reload or refresh in your browser</b> (and OK any request to re-send the form +data) to complete your [% terms.bug %] change. Once this maintenance is +complete, your change will succeed and you won't get this page any more. +</p> + +<p> +Only updates to [% terms.bugs %] are being blocked by this page, any other +activities in [% terms.Bugzilla %] are still fair game. <a href="index.cgi" +target="_blank">Open [% terms.Bugzilla %] in a new tab/window</a> if you'd +like, to continue working on other things while waiting. +</p> +</div> +</body> +</html> diff --git a/template/en/default/bug/show-multiple.html.tmpl b/template/en/default/bug/show-multiple.html.tmpl index 33dde14a3..03ce294c5 100644 --- a/template/en/default/bug/show-multiple.html.tmpl +++ b/template/en/default/bug/show-multiple.html.tmpl @@ -180,6 +180,7 @@ [% USE Bugzilla %] [% field_counter = 0 %] [% FOREACH field = Bugzilla.active_custom_fields %] + [% NEXT IF cf_hidden_in_product(field.name, bug.product, bug.component) %] [% field_counter = field_counter + 1 %] [%# Odd-numbered fields get an opening <tr> %] [% '<tr>' IF field_counter % 2 %] diff --git a/template/en/default/bug/show.xml.tmpl b/template/en/default/bug/show.xml.tmpl index dae207f26..cb323d229 100644 --- a/template/en/default/bug/show.xml.tmpl +++ b/template/en/default/bug/show.xml.tmpl @@ -20,8 +20,10 @@ # #%] [% PROCESS bug/time.html.tmpl %] +[% USE Bugzilla %] +[% cgi = Bugzilla.cgi %] <?xml version="1.0" [% IF Param('utf8') %]encoding="UTF-8" [% END %]standalone="yes" ?> -<!DOCTYPE bugzilla SYSTEM "[% urlbase FILTER html %]bugzilla.dtd"> +<!DOCTYPE bugzilla [% IF cgi.param('dtd') %][[% PROCESS pages/bugzilla.dtd.tmpl %]][% ELSE %]SYSTEM "[% urlbase FILTER xml %]page.cgi?id=bugzilla.dtd"[% END %]> <bugzilla version="[% constants.BUGZILLA_VERSION %]" urlbase="[% urlbase FILTER xml %]" @@ -142,6 +144,7 @@ [% ELSIF field == "see_also" %] [% val = val.name %] [% END %] + [% NEXT IF cf_hidden_in_product(field.name, bug.product, bug.component) %] <[% field %][% IF name != '' %] name="[% name FILTER xml %]"[% END -%]> [%- val FILTER xml %]</[% field %]> [% END %] diff --git a/template/en/default/config.rdf.tmpl b/template/en/default/config.rdf.tmpl index 15f784ce8..d7b282776 100644 --- a/template/en/default/config.rdf.tmpl +++ b/template/en/default/config.rdf.tmpl @@ -171,9 +171,8 @@ [% IF show_flags %] <bz:flag_types> <Seq> - [% flag_types = component.flag_types.bug.merge(component.flag_types.attachment) %] + [% flag_types = component.flag_types(is_active=>1).bug.merge(component.flag_types(is_active=>1).attachment) %] [% FOREACH flag_type = flag_types %] - [% NEXT UNLESS flag_type.is_active %] [% all_visible_flag_types.${flag_type.id} = flag_type %] <li resource="[% escaped_urlbase %]flag.cgi?id=[% flag_type.id FILTER uri %]&name=[% flag_type.name FILTER uri %]" /> diff --git a/template/en/default/email/bugmail.txt.tmpl b/template/en/default/email/bugmail.txt.tmpl index 2d20aff7c..7c0bace4a 100644 --- a/template/en/default/email/bugmail.txt.tmpl +++ b/template/en/default/email/bugmail.txt.tmpl @@ -22,9 +22,15 @@ [% PROCESS "global/field-descs.none.tmpl" %] [% PROCESS "global/reason-descs.none.tmpl" %] +[% show_new = isnew + && (to_user.settings.bugmail_new_prefix.value == 'on') %] [% isnew = bug.lastdiffed ? 0 : 1 %] +[% UNLESS to_user.settings.product_chooser.value == 'full_product_chooser' %] +Do not reply to this email. You can add comments to this [% terms.bug %] at +[% END %] + [%+ PROCESS generate_diffs -%] [% FOREACH comment = new_comments %] diff --git a/template/en/default/global/header.html.tmpl b/template/en/default/global/header.html.tmpl index a7449883f..480197431 100644 --- a/template/en/default/global/header.html.tmpl +++ b/template/en/default/global/header.html.tmpl @@ -239,8 +239,7 @@ [%# Required for the 'Autodiscovery' feature in Firefox 2 and IE 7. %] <link rel="search" type="application/opensearchdescription+xml" - title="[% terms.Bugzilla %]" href="./search_plugin.cgi"> - <link rel="shortcut icon" href="images/favicon.ico" > + title="[% terms.BugzillaTitle %]" href="./search_plugin.cgi"> [% Hook.process("additional_header") %] </head> @@ -265,7 +264,7 @@ <table border="0" cellspacing="0" cellpadding="0" id="titles"> <tr> <td id="title"> - <p>[% terms.Bugzilla %] + <p>[% terms.BugzillaTitle %] [% " – $header" IF header %]</p> </td> diff --git a/template/en/default/global/setting-descs.none.tmpl b/template/en/default/global/setting-descs.none.tmpl index a0b11f048..52d1c9803 100644 --- a/template/en/default/global/setting-descs.none.tmpl +++ b/template/en/default/global/setting-descs.none.tmpl @@ -52,6 +52,7 @@ "email_format" => "Preferred email format", "html" => "HTML", "text_only" => "Text Only", + "bugmail_new_prefix" => "Add 'New:' to subject line of email sent when a new $terms.bug is filed", } %] diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl index 35640b220..5310952f2 100644 --- a/template/en/default/global/user-error.html.tmpl +++ b/template/en/default/global/user-error.html.tmpl @@ -1342,6 +1342,40 @@ [% END %] </ul> + [% ELSIF error == "password_not_complex" %] + [% title = "Password Fails Requirements" %] + [% passregex = Param('password_complexity') %] + Password must contain at least one: + <ul> + [% IF passregex.search('letters') %] + <li>UPPERCASE letter</li> + <li>lowercase letter</li> + [% END %] + [% IF passregex.search('numbers') %] + <li>digit</li> + [% END %] + [% IF passregex.search('specialchars') %] + <li>special character</li> + [% END %] + </ul> + + [% ELSIF error == "password_not_complex" %] + [% title = "Password Fails Requirements" %] + [% passregex = Param('password_complexity') %] + Password must contain at least one: + <ul> + [% IF passregex.search('letters') %] + <li>UPPERCASE letter</li> + <li>lowercase letter</li> + [% END %] + [% IF passregex.search('numbers') %] + <li>digit</li> + [% END %] + [% IF passregex.search('specialchars') %] + <li>special character</li> + [% END %] + </ul> + [% ELSIF error == "product_access_denied" %] [% title = "Product Access Denied" %] Either the product diff --git a/template/en/default/global/user.html.tmpl b/template/en/default/global/user.html.tmpl index df902b451..a6be5eee9 100644 --- a/template/en/default/global/user.html.tmpl +++ b/template/en/default/global/user.html.tmpl @@ -27,6 +27,9 @@ [% FILTER collapse %] [% IF user.id %] <a class="email" href="mailto:[% who.email FILTER html %]" + [% IF user.in_group('editusers') || user.bless_groups.size > 0 %] + onclick="show_admin_username(event, [% who.id FILTER none %], '[% who.email FILTER js %]'); return false" + [% END %] title="[% who.identity FILTER html %]"> [%- END -%] [% IF who.name %] diff --git a/template/en/default/list/edit-multiple.html.tmpl b/template/en/default/list/edit-multiple.html.tmpl index 92e578e8f..7c7d99408 100644 --- a/template/en/default/list/edit-multiple.html.tmpl +++ b/template/en/default/list/edit-multiple.html.tmpl @@ -282,8 +282,9 @@ [% USE Bugzilla %] [%# Show all legal values and all fields, ignoring visibility controls. %] - [% bug = 0 %] + [% bug = default.defined ? default : 0 %] [% FOREACH field = Bugzilla.active_custom_fields %] + [% NEXT IF cf_hidden_in_product(field.name, one_product, components) %] <tr> [% PROCESS bug/field.html.tmpl value = dontchange editable = 1 @@ -427,6 +428,7 @@ [% FOREACH r = resolutions %] [% NEXT IF !r %] [% NEXT IF r == "DUPLICATE" || r == "MOVED" %] + [% NEXT IF r == "EXPIRED" AND user.login != "gerv@mozilla.org" %] <option value="[% r FILTER html %]">[% display_value("resolution", r) FILTER html %]</option> [% END %] </select> diff --git a/template/en/default/list/list.html.tmpl b/template/en/default/list/list.html.tmpl index 28540cdc0..4120fc228 100644 --- a/template/en/default/list/list.html.tmpl +++ b/template/en/default/list/list.html.tmpl @@ -42,10 +42,11 @@ [%# Page Header #%] [%############################################################################%] +[% url_filtered_title = title FILTER url_quote %] [% PROCESS global/header.html.tmpl title = title style = style - atomlink = "buglist.cgi?$urlquerypart&title=$title&ctype=atom" + atomlink = "buglist.cgi?$urlquerypart&title=$url_filtered_title&ctype=atom" yui = [ 'autocomplete', 'calendar' ] javascript_urls = [ "js/util.js", "js/field.js" ] style_urls = [ "skins/standard/buglist.css" ] @@ -197,7 +198,7 @@ [% urlquerypart FILTER html %]&ctype=csv&human=1">CSV</a> | <a href="buglist.cgi? [% urlquerypart FILTER html %]&title= - [%- title FILTER html %]&ctype=atom">Feed</a> | + [%- title FILTER url_quote %]&ctype=atom">Feed</a> | <a href="buglist.cgi? [% urlquerypart FILTER html %]&ctype=ics">iCalendar</a> | <a href="colchange.cgi? diff --git a/template/en/default/list/table.html.tmpl b/template/en/default/list/table.html.tmpl index 2b266d4ce..c2964f17c 100644 --- a/template/en/default/list/table.html.tmpl +++ b/template/en/default/list/table.html.tmpl @@ -80,12 +80,15 @@ [%############################################################################%] [% tableheader = BLOCK %] - <table class="bz_buglist" cellspacing="0" cellpadding="4" width="100%"> + <table class="bz_buglist sortable" cellspacing="0" cellpadding="4" width="100%"> + <thead> <tr class="bz_buglist_header bz_first_buglist_header"> [% IF dotweak %] <th> </th> [% END %] - <th colspan="[% splitheader ? 2 : 1 %]" class="first-child"> + <th colspan="[% splitheader ? 2 : 1 %]" class="first-child + sortable_column_0 + sorted_[% lsearch(order_columns, 'bug_id') FILTER html %]"> <a href="buglist.cgi? [% urlquerypart FILTER html %]&order= [% PROCESS new_order id='bug_id' %] @@ -100,7 +103,7 @@ [% FOREACH id = displaycolumns %] [% NEXT UNLESS loop.count() % 2 == 0 %] [% column = columns.$id %] - [% PROCESS columnheader %] + [% PROCESS columnheader key=loop.count() %] [% END %] </tr><tr class="bz_buglist_header"> @@ -112,7 +115,7 @@ [% FOREACH id = displaycolumns %] [% NEXT IF loop.count() % 2 == 0 %] [% column = columns.$id %] - [% PROCESS columnheader %] + [% PROCESS columnheader key=loop.count() %] [% END %] [% ELSE %] @@ -125,10 +128,13 @@ [% END %] </tr> + </thead> [% END %] [% BLOCK columnheader %] - <th colspan="[% splitheader ? 2 : 1 %]"> + <th colspan="[% splitheader ? 2 : 1 %]" + class="sortable_column_[% key FILTER html %] + sorted_[% lsearch(order_columns, id) FILTER html %]"> <a href="buglist.cgi?[% urlquerypart FILTER html %]&order= [% PROCESS new_order %] [%-#%]&query_based_on= @@ -168,6 +174,7 @@ [% tableheader %] +<tbody class="sorttable_body"> [% FOREACH bug = bugs %] [% count = loop.count() %] @@ -193,7 +200,17 @@ [% FOREACH column = displaycolumns %] <td [% 'style="white-space: nowrap"' IF NOT abbrev.$column.wrap %] - class="bz_[% column FILTER css_class_quote %]_column"> + class="bz_[% column FILTER css_class_quote %]_column" + [% SWITCH column %] + [% CASE 'opendate' %] + sorttable_customkey="[% bug.opentime FILTER html %]" + [% CASE 'changeddate' %] + sorttable_customkey="[% bug.changedtime FILTER html %]" + [% CASE columns_sortkey.keys %] + [% SET sortkey = columns_sortkey.$column.${bug.$column} %] + sorttable_customkey="[% sortkey FILTER html %]" + [% END %] + > [% IF abbrev.$column.maxlength %] <span title="[%- display_value(column, bug.$column) FILTER html %]"> [% END %] @@ -228,6 +245,7 @@ [% END %] [% END %] +</tbody> </table> diff --git a/template/en/default/pages/bugzilla.dtd.tmpl b/template/en/default/pages/bugzilla.dtd.tmpl new file mode 100644 index 000000000..f7fc1b4ad --- /dev/null +++ b/template/en/default/pages/bugzilla.dtd.tmpl @@ -0,0 +1,179 @@ +[%# The contents of this file are subject to the Mozilla Public + # License Version 1.1 (the "License"); you may not use this file + # except in compliance with the License. You may obtain a copy of + # the License at http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS + # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + # implied. See the License for the specific language governing + # rights and limitations under the License. + # + # The Original Code is the Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is Netscape Communications + # Corporation. Portions created by Netscape are + # Copyright (C) 1998 Netscape Communications Corporation. All + # Rights Reserved. + # + # Contributor(s): Dawn Endico <endico@mozilla.org> + # Dave Miller <justdave@syndicomm.com> + # Bradley Baetz <bbaetz@student.usyd.edu.au> + # Myk Mylez <myk@mozilla.org> + # Colin Ogilvie <mozilla@colinogilvie.co.uk> + # Joel Peshkin <bugreport@peshkin.net> + # Frédéric Buclin <LpSolit@gmail.com> + # Gervase Markham <gerv@gerv.net> + # Max Kanat-Alexander <mkanat@bugzilla.org> + # David Lawrence <dkl@mozilla.com> + # + #%] +[% USE Bugzilla %] +<!ELEMENT [% "bugzilla" %] (bug+)> +<!ATTLIST [% "bugzilla" %] + version CDATA #REQUIRED + urlbase CDATA #REQUIRED + maintainer CDATA #REQUIRED + exporter CDATA #IMPLIED +> +<!ELEMENT [% "bug" %] (bug_id, + (alias?, + creation_ts, + short_desc, + delta_ts, + reporter_accessible, + cclist_accessible, + classification_id, + classification, + product, + component, + version, + rep_platform, + op_sys, + bug_status, + resolution?, + dup_id?, + see_also*, + bug_file_loc?, + status_whiteboard?, + keywords*, + priority, + bug_severity, + target_milestone?, + dependson*, + blocked*, + everconfirmed, + reporter, + assigned_to, + cc*, + (estimated_time, + remaining_time, + actual_time, + deadline?)?, + qa_contact?, +[% FOREACH field = Bugzilla.active_custom_fields %] + [%+ field.name FILTER xml -%] + [%- IF field.type == constants.FIELD_TYPE_MULTI_SELECT %]*[% ELSE %]?[% END %], +[% END %] + votes?, + token?, + group*, + flag*, + long_desc*, + attachment*)?)> +<!ATTLIST [% "bug" %] + error (NotFound | NotPermitted | InvalidBugId) #IMPLIED +> +<!ELEMENT bug_id (#PCDATA)> +<!ELEMENT alias (#PCDATA)> +<!ELEMENT reporter_accessible (#PCDATA)> +<!ELEMENT cclist_accessible (#PCDATA)> +<!ELEMENT exporter (#PCDATA)> +<!ELEMENT urlbase (#PCDATA)> +<!ELEMENT bug_status (#PCDATA)> +<!ELEMENT classification_id (#PCDATA)> +<!ELEMENT classification (#PCDATA)> +<!ELEMENT product (#PCDATA)> +<!ELEMENT priority (#PCDATA)> +<!ELEMENT version (#PCDATA)> +<!ELEMENT rep_platform (#PCDATA)> +<!ELEMENT assigned_to (#PCDATA)> +<!ATTLIST assigned_to + name CDATA #REQUIRED +> +<!ELEMENT delta_ts (#PCDATA)> +<!ELEMENT component (#PCDATA)> +<!ELEMENT reporter (#PCDATA)> +<!ATTLIST reporter + name CDATA #REQUIRED +> +<!ELEMENT target_milestone (#PCDATA)> +<!ELEMENT bug_severity (#PCDATA)> +<!ELEMENT creation_ts (#PCDATA)> +<!ELEMENT qa_contact (#PCDATA)> +<!ATTLIST qa_contact + name CDATA #REQUIRED +> +<!ELEMENT status_whiteboard (#PCDATA)> +<!ELEMENT op_sys (#PCDATA)> +<!ELEMENT resolution (#PCDATA)> +<!ELEMENT dup_id (#PCDATA)> +<!ELEMENT bug_file_loc (#PCDATA)> +<!ELEMENT short_desc (#PCDATA)> +<!ELEMENT keywords (#PCDATA)> +<!ELEMENT dependson (#PCDATA)> +<!ELEMENT blocked (#PCDATA)> +<!ELEMENT everconfirmed (#PCDATA)> +<!ELEMENT cc (#PCDATA)> +<!ELEMENT see_also (#PCDATA)> +<!ELEMENT votes (#PCDATA)> +<!ELEMENT token (#PCDATA)> +<!ELEMENT group (#PCDATA)> +<!ATTLIST group + id CDATA #REQUIRED +> +<!ELEMENT estimated_time (#PCDATA)> +<!ELEMENT remaining_time (#PCDATA)> +<!ELEMENT actual_time (#PCDATA)> +<!ELEMENT deadline (#PCDATA)> +[% FOREACH field = Bugzilla.active_custom_fields %] +<!ELEMENT [% field.name FILTER xml %] (#PCDATA)> +[% END %] +<!ELEMENT long_desc (commentid, attachid?, who, bug_when, work_time?, thetext)> +<!ATTLIST long_desc + isprivate (0|1) #REQUIRED +> +<!ELEMENT commentid (#PCDATA)> +<!ELEMENT who (#PCDATA)> +<!ATTLIST who + name CDATA #REQUIRED +> +<!ELEMENT bug_when (#PCDATA)> +<!ELEMENT work_time (#PCDATA)> +<!ELEMENT thetext (#PCDATA)> +<!ELEMENT attachment (attachid, date, delta_ts, desc, filename, type, size, attacher, token?, data?, flag*)> +<!ATTLIST attachment + isobsolete (0|1) #REQUIRED + ispatch (0|1) #REQUIRED + isprivate (0|1) #REQUIRED + isurl (0|1) #REQUIRED +> +<!ELEMENT attacher (#PCDATA)> +<!ELEMENT attachid (#PCDATA)> +<!ELEMENT date (#PCDATA)> +<!ELEMENT desc (#PCDATA)> +<!ELEMENT filename (#PCDATA)> +<!ELEMENT type (#PCDATA)> +<!ELEMENT size (#PCDATA)> +<!ELEMENT data (#PCDATA)> +<!ATTLIST data + encoding (base64) #IMPLIED +> +<!ELEMENT flag EMPTY> +<!ATTLIST flag + name CDATA #REQUIRED + id CDATA #REQUIRED + type_id CDATA #REQUIRED + status CDATA #REQUIRED + setter CDATA #REQUIRED + requestee CDATA #IMPLIED +> diff --git a/template/en/default/pages/fields.html.tmpl b/template/en/default/pages/fields.html.tmpl index 2794e1cc4..568245653 100644 --- a/template/en/default/pages/fields.html.tmpl +++ b/template/en/default/pages/fields.html.tmpl @@ -62,34 +62,41 @@ </dt> <dd class="unconfirmed"> This [% terms.bug %] has recently been added to the database. - Nobody has confirmed that this [% terms.bug %] is valid. Users + Nobody has validated that this [% terms.bug %] is true. Users who have the "canconfirm" permission set may confirm - this [% terms.bug %], changing its state to - <b>[% display_value("bug_status", "CONFIRMED") FILTER html %]</b>. - Or, it may be directly resolved and marked + this [% terms.bug %], changing its state to [% display_value("bug_status", "NEW") FILTER html %]. Or, it may be + directly resolved and marked [% display_value("bug_status", "RESOLVED") FILTER html %]. + </dd> + <dt> + <b>[% display_value("bug_status", "NEW") FILTER html %]</b> + </dt> + <dd> + This [% terms.bug %] has recently been added to the assignee's + list of [% terms.bugs %] and must be processed. [% terms.Bugs %] in + this state may be accepted, and become <b>[% display_value("bug_status", "ASSIGNED") FILTER html %]</b>, passed + on to someone else, and remain <b>[% display_value("bug_status", "NEW") FILTER html %]</b>, or resolved and marked <b>[% display_value("bug_status", "RESOLVED") FILTER html %]</b>. </dd> - <dt class="confirmed"> - [% display_value("bug_status", "CONFIRMED") FILTER html %] + <dt> + <b>[% display_value("bug_status", "ASSIGNED") FILTER html %]</b> </dt> - <dd class="confirmed"> - This [% terms.bug %] is valid and has recently been filed. - [%+ terms.Bugs %] in this state become - <b>[% display_value("bug_status", "IN_PROGRESS") FILTER html %]</b> - when somebody is working on them, or become resolved and marked - <b>[% display_value("bug_status", "RESOLVED") FILTER html %]</b>. + <dd> + This [% terms.bug %] is not yet resolved, but is assigned to the + proper person. From here [% terms.bugs %] can be given to another + person and become <b>[% display_value("bug_status", "NEW") FILTER html %]</b>, or + resolved and become <b>[% display_value("bug_status", "RESOLVED") FILTER html %]</b>. </dd> - <dt class="in_progress"> - [% display_value("bug_status", "IN_PROGRESS") FILTER html %] + <dt> + <b>[% display_value("bug_status", "REOPENED") FILTER html %]</b> </dt> - <dd class="in_progress"> - This [% terms.bug %] is not yet resolved, but is assigned to the - proper person who is working on the [% terms.bug %]. From here, - [%+ terms.bugs %] can be given to another person and become - <b>[% display_value("bug_status", "CONFIRMED") FILTER html %]</b>, or - resolved and become + <dd> + This [% terms.bug %] was once resolved, but the resolution was + deemed incorrect. For example, a <b>[% display_value("resolution", "WORKSFORME") FILTER html %]</b> [% terms.bug %] is + <b>[% display_value("bug_status", "REOPENED") FILTER html %]</b> when more information shows up and + the [% terms.bug %] is now reproducible. From here [% terms.bugs %] are + either marked <b>[% display_value("bug_status", "ASSIGNED") FILTER html %]</b> or <b>[% display_value("bug_status", "RESOLVED") FILTER html %]</b>. </dd> @@ -124,9 +131,10 @@ [% display_value("bug_status", "VERIFIED") FILTER html %] </dt> <dd class="verified"> - QA has looked at the [% terms.bug %] and the resolution and - agrees that the appropriate resolution has been taken. This is - the final status for [% terms.bugs %]. + QA has looked at the [% terms.bug %] and the resolution and + agrees that the appropriate resolution has been taken. + Any zombie [% terms.bugs %] who choose to walk the earth again must + do so by becoming <b>[% display_value("bug_status", "REOPENED") FILTER html %]</b>. </dd> [% Hook.process('closed-status') %] @@ -163,10 +171,9 @@ </dt> <dd class="duplicate"> The problem is a duplicate of an existing [% terms.bug %]. - When [% terms.abug %] is marked as a - <b>[% display_value("resolution", "DUPLICATE") FILTER html %]</b>, - you will see which [% terms.bug %] it is a duplicate of, - next to the resolution. + Marking [% terms.abug %] duplicate requires the [% terms.bug %]# + of the duplicating [% terms.bug %] and will at least put + that [% terms.bug %] number in the description field. </dd> <dt class="worksforme"> diff --git a/template/en/default/request/email.txt.tmpl b/template/en/default/request/email.txt.tmpl index fb957484b..989e0c4e3 100644 --- a/template/en/default/request/email.txt.tmpl +++ b/template/en/default/request/email.txt.tmpl @@ -25,7 +25,8 @@ [% bugidsummary = bug.bug_id _ ': ' _ bug.short_desc %] [% attidsummary = attachment.id _ ': ' _ attachment.description %] [% flagtype_name = flag ? flag.type.name : old_flag.type.name %] -[% statuses = { '+' => "granted" , '-' => 'denied' , 'X' => "canceled" , +[%# Upstreaming: denied (bug 621883) %] +[% statuses = { '+' => "granted" , '-' => 'not granted' , 'X' => "canceled" , '?' => "asked" } %] [% to_identity = "" %] diff --git a/template/en/default/search/field.html.tmpl b/template/en/default/search/field.html.tmpl index defc94cc3..19f199692 100644 --- a/template/en/default/search/field.html.tmpl +++ b/template/en/default/search/field.html.tmpl @@ -115,7 +115,7 @@ <select name="[% field.name FILTER html%]" id="[% field.name FILTER html %]" [% IF onchange %] onchange="[% onchange FILTER html %]"[% END %] - multiple="multiple" size="7"> + multiple="multiple" size="9"> [% legal_values = ${field.name} %] [% IF field.name == "component" %] [% legal_values = ${"component_"} %] diff --git a/template/en/default/search/search-google.html.tmpl b/template/en/default/search/search-google.html.tmpl new file mode 100644 index 000000000..080887abb --- /dev/null +++ b/template/en/default/search/search-google.html.tmpl @@ -0,0 +1,57 @@ +[%# The contents of this file are subject to the Mozilla Public + # License Version 1.1 (the "License"); you may not use this file + # except in compliance with the License. You may obtain a copy of + # the License at http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS + # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + # implied. See the License for the specific language governing + # rights and limitations under the License. + # + # The Original Code is the Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is the Mozilla Foundation + # Portions created by the Initial Developers are Copyright (C) 2011 the + # Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Dave Lawrence <dkl@mozilla.com> + #%] + +[% PROCESS global/variables.none.tmpl %] + +[% PROCESS global/header.html.tmpl + title = "Search " _ terms.Bugs _ " using Google" +%] + +[% WRAPPER search/tabs.html.tmpl %] + +<p> + Use the <a href="http://www.google.com">Google</a> search engine to search + for [% terms.Bugzilla +%] [%+ terms.bugs %]. Find the [% terms.bugs %] you are + looking for by entering words that best describe it. +</p> + +<p> + For example, if the [% terms.bug %] you are looking for is a browser crash when + you go to a secure web site with an embedded Flash animation, you might search + for "crash secure SSL flash". +</p> + +<p> + <span style="color:red;">*</span> + Google only indexes publicly viewable [% terms.bugs %] and all may not be represented. +<p> + +<form method="get" action="http://www.google.com/search"> +<input type="hidden" name="sitesearch" value="bugzilla.mozilla.org"> + <nobr> + <input type="text" name="q" size="60" maxlength="255" value=""> + <input type="submit" value="Search"> + </nobr> +</form> + +[% END %] + +[% PROCESS global/footer.html.tmpl %] + diff --git a/template/en/default/search/search-specific.html.tmpl b/template/en/default/search/search-specific.html.tmpl index 31d950ec5..277a90960 100644 --- a/template/en/default/search/search-specific.html.tmpl +++ b/template/en/default/search/search-specific.html.tmpl @@ -98,7 +98,7 @@ for "crash secure SSL flash". <label for="content">Words:</label> </th> <td> - <input name="content" size="40" id="content" + <input name="content" size="60" id="content" value="[% default.content.0 FILTER html %]"> <script type="text/javascript"> <!-- document.forms['queryform'].content.focus(); @@ -107,6 +107,15 @@ for "crash secure SSL flash". </td> </tr> <tr> + <td> </td> + <td> + <input type="hidden" name="comments" value="0"> + <input type="checkbox" id="comments" name="comments" + value="1" [% 'checked' IF cgi.param("comments") %]> + <label for="comments">Search comments</label> + </td> + </tr> + <tr> <td></td> <td> diff --git a/template/en/default/search/tabs.html.tmpl b/template/en/default/search/tabs.html.tmpl index 119b30fde..6a2f7f70a 100644 --- a/template/en/default/search/tabs.html.tmpl +++ b/template/en/default/search/tabs.html.tmpl @@ -27,7 +27,9 @@ tabs = [ { name => 'specific', label => "Simple Search", link => "query.cgi?format=specific" }, { name => 'advanced', label => "Advanced Search", - link => "query.cgi?format=advanced" } ] + link => "query.cgi?format=advanced" }, + { name => 'google', label => 'Google Search', + link => "query.cgi?format=google" } ] current_tab_name = query_format || format || "advanced" %] |