diff options
47 files changed, 1132 insertions, 84 deletions
diff --git a/Bugzilla/Attachment.pm b/Bugzilla/Attachment.pm index 33183797b..14c81193d 100644 --- a/Bugzilla/Attachment.pm +++ b/Bugzilla/Attachment.pm @@ -501,9 +501,8 @@ sub _check_content_type { # If we have autodetected application/octet-stream from the Content-Type # header, let's have a better go using a sniffer if available. - if (defined Bugzilla->input_params->{contenttypemethod} - && Bugzilla->input_params->{contenttypemethod} eq 'autodetect' - && $content_type eq 'application/octet-stream' + if ((Bugzilla->input_params->{contenttypemethod} // '') eq 'autodetect' + && ($content_type eq 'application/octet-stream' || $content_type =~ m{text/x-}) && Bugzilla->feature('typesniffer')) { import File::MimeInfo::Magic qw(mimetype); @@ -534,8 +533,7 @@ sub _check_content_type { # Make sure patches are viewable in the browser if (!ref($invocant) - && defined Bugzilla->input_params->{contenttypemethod} - && Bugzilla->input_params->{contenttypemethod} eq 'autodetect' + && (Bugzilla->input_params->{contenttypemethod} // '') eq 'autodetect' && $content_type =~ m{text/x-(?:diff|patch)}) { $params->{ispatch} = 1; diff --git a/Bugzilla/Auth/Verify/LDAP.pm b/Bugzilla/Auth/Verify/LDAP.pm index e37f55793..9687363d6 100644 --- a/Bugzilla/Auth/Verify/LDAP.pm +++ b/Bugzilla/Auth/Verify/LDAP.pm @@ -163,7 +163,8 @@ sub ldap { ThrowCodeError("ldap_server_not_defined") unless @servers; foreach (@servers) { - $self->{ldap} = new Net::LDAP(trim($_)); + # The 'raw' attribute is used to make sure that data is correctly decoded. + $self->{ldap} = new Net::LDAP(trim($_), raw => ';binary'); last if $self->{ldap}; } ThrowCodeError("ldap_connect_failed", { server => join(", ", @servers) }) diff --git a/Bugzilla/Bug.pm b/Bugzilla/Bug.pm index 8b4493f85..00231c1c5 100644 --- a/Bugzilla/Bug.pm +++ b/Bugzilla/Bug.pm @@ -1848,6 +1848,20 @@ sub _check_keywords { my $obj = Bugzilla::Keyword->check($keyword); $keywords{$obj->id} = $obj; } + + my %old_kw_id; + if (blessed $invocant) { + my @old_keywords = @{$invocant->keyword_objects}; + %old_kw_id = map { $_->id => 1 } @old_keywords; + } + + foreach my $keyword (values %keywords) { + next if $keyword->is_active || exists $old_kw_id{$keyword->id}; + + ThrowUserError('value_inactive', + { value => $keyword->name, class => ref $keyword }); + } + return [values %keywords]; } diff --git a/Bugzilla/DB/Schema.pm b/Bugzilla/DB/Schema.pm index d1c1dc7e9..d2742bc73 100644 --- a/Bugzilla/DB/Schema.pm +++ b/Bugzilla/DB/Schema.pm @@ -587,6 +587,8 @@ use constant ABSTRACT_SCHEMA => { PRIMARYKEY => 1}, name => {TYPE => 'varchar(64)', NOTNULL => 1}, description => {TYPE => 'MEDIUMTEXT', NOTNULL => 1}, + is_active => {TYPE => 'BOOLEAN', NOTNULL => 1, + DEFAULT => 'TRUE'}, ], INDEXES => [ keyworddefs_name_idx => {FIELDS => ['name'], @@ -604,7 +606,6 @@ use constant ABSTRACT_SCHEMA => { REFERENCES => {TABLE => 'keyworddefs', COLUMN => 'id', DELETE => 'CASCADE'}}, - ], INDEXES => [ keywords_bug_id_idx => {FIELDS => [qw(bug_id keywordid)], diff --git a/Bugzilla/Install/DB.pm b/Bugzilla/Install/DB.pm index ed2539251..f7fd8b2ab 100644 --- a/Bugzilla/Install/DB.pm +++ b/Bugzilla/Install/DB.pm @@ -732,6 +732,10 @@ sub update_table_definitions { # 2015-12-16 LpSolit@gmail.com - Bug 1232578 _sanitize_audit_log_table(); + # 2014-11-18 dylan@mozilla.com - Bug 69267 + $dbh->bz_add_column('keyworddefs', 'is_active', + {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'TRUE'}); + ################################################################ # New --TABLE-- changes should go *** A B O V E *** this point # ################################################################ diff --git a/Bugzilla/Keyword.pm b/Bugzilla/Keyword.pm index afa93e1e9..ef044a0c5 100644 --- a/Bugzilla/Keyword.pm +++ b/Bugzilla/Keyword.pm @@ -26,6 +26,7 @@ use constant DB_COLUMNS => qw( keyworddefs.id keyworddefs.name keyworddefs.description + keyworddefs.is_active ); use constant DB_TABLE => 'keyworddefs'; @@ -33,11 +34,13 @@ use constant DB_TABLE => 'keyworddefs'; use constant VALIDATORS => { name => \&_check_name, description => \&_check_description, + is_active => \&_check_is_active, }; use constant UPDATE_COLUMNS => qw( name description + is_active ); ############################### @@ -62,6 +65,7 @@ sub bug_count { sub set_name { $_[0]->set('name', $_[1]); } sub set_description { $_[0]->set('description', $_[1]); } +sub set_is_active { $_[0]->set('is_active', $_[1]); } ############################### #### Subroutines ###### @@ -125,6 +129,10 @@ sub _check_description { return $desc; } +sub _check_is_active { return $_[1] ? 1 : 0 } + +sub is_active { return $_[0]->{is_active} } + 1; __END__ @@ -145,13 +153,13 @@ Bugzilla::Keyword - A Keyword that can be added to a bug. Bugzilla::Keyword represents a keyword that can be added to a bug. -This implements all standard C<Bugzilla::Object> methods. See +This implements all standard C<Bugzilla::Object> methods. See L<Bugzilla::Object> for more details. -=head1 SUBROUTINES +=head1 METHODS -This is only a list of subroutines specific to C<Bugzilla::Keyword>. -See L<Bugzilla::Object> for more subroutines that this object +This is only a list of methods specific to C<Bugzilla::Keyword>. +See L<Bugzilla::Object> for more methods that this object implements. =over @@ -166,6 +174,18 @@ implements. Returns: A reference to an array of Keyword objects, or an empty arrayref if there are no keywords. +=item C<is_active> + + Description: Indicates if the keyword may be used on a bug + Params: none + Returns: a boolean value that is true if the keyword can be applied to bugs. + +=item C<set_is_active($is_active)> + + Description: Set the is_active property to a boolean value + Params: the new value of the is_active property. + Returns: nothing + =back =cut diff --git a/Bugzilla/Template.pm b/Bugzilla/Template.pm index 41b9265c6..95882b65f 100644 --- a/Bugzilla/Template.pm +++ b/Bugzilla/Template.pm @@ -1122,11 +1122,16 @@ sub create { # Whether or not keywords are enabled, in this Bugzilla. 'use_keywords' => sub { return Bugzilla::Keyword->any_exist; }, - # All the keywords. + # All the keywords 'all_keywords' => sub { return [map { $_->name } Bugzilla::Keyword->get_all()]; }, + # All the active keywords + 'active_keywords' => sub { + return [map { $_->name } grep { $_->is_active } Bugzilla::Keyword->get_all()]; + }, + 'feature_enabled' => sub { return Bugzilla->feature(@_); }, # field_descs can be somewhat slow to generate, so we generate diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm index 77e6cebb0..1768d7c48 100644 --- a/Bugzilla/User.pm +++ b/Bugzilla/User.pm @@ -2132,10 +2132,16 @@ sub wants_mail { $relationship = REL_ANY; } + my $wants_mail; + Bugzilla::Hook::process('user_wants_mail', { events => $events, + relationship => $relationship, + wants_mail => \$wants_mail }); + return $wants_mail if defined $wants_mail; + # Skip DB query if relationship is explicit return 1 if $relationship == REL_GLOBAL_WATCHER; - my $wants_mail = grep { $self->mail_settings->{$relationship}{$_} } @$events; + $wants_mail = grep { $self->mail_settings->{$relationship}{$_} } @$events; return $wants_mail ? 1 : 0; } diff --git a/Bugzilla/WebService/Bug.pm b/Bugzilla/WebService/Bug.pm index b07d3cb01..34e6b6662 100644 --- a/Bugzilla/WebService/Bug.pm +++ b/Bugzilla/WebService/Bug.pm @@ -245,6 +245,7 @@ sub _legal_field_values { elsif ($field_name eq 'keywords') { my @legal_keywords = Bugzilla::Keyword->get_all; foreach my $value (@legal_keywords) { + next unless $value->is_active; push (@result, { name => $self->type('string', $value->name), description => $self->type('string', $value->description), diff --git a/buglist.cgi b/buglist.cgi index daee34c9b..ea6aa6ee5 100755 --- a/buglist.cgi +++ b/buglist.cgi @@ -858,9 +858,44 @@ if (@bugidlist) { while (my ($bug_id, $min_membercontrol) = $sth->fetchrow_array()) { $min_membercontrol{$bug_id} = $min_membercontrol || CONTROLMAPNA; } + + my $involved_bugs = {}; + my $involved_new_bugs = {}; + + if ($user->id) { + $involved_bugs = + $dbh->selectall_hashref('SELECT bugs.bug_id, CASE WHEN last_visit_ts < delta_ts THEN 1 ELSE 0 END AS updated + FROM bugs + INNER JOIN bug_user_last_visit + ON bugs.bug_id = bug_user_last_visit.bug_id + WHERE user_id = ? + AND ' . $dbh->sql_in('bugs.bug_id', \@bugidlist), + 'bug_id', undef, $user->id); + + my ($new_bugs) = diff_arrays(\@bugidlist, [keys %$involved_bugs]); + if (@$new_bugs) { + my $involved_new_bugs_list = + $dbh->selectcol_arrayref('SELECT bugs.bug_id + FROM bugs + LEFT JOIN cc + ON cc.bug_id = bugs.bug_id AND who = ? + WHERE (reporter = ? OR assigned_to = ? OR qa_contact = ? OR who = ?) + AND ' . $dbh->sql_in('bugs.bug_id', $new_bugs), + undef, ($user->id) x 5); + %$involved_new_bugs = map { $_ => 1 } @$involved_new_bugs_list; + } + } + foreach my $bug (@bugs) { - next unless defined($min_membercontrol{$bug->{'bug_id'}}); - if ($min_membercontrol{$bug->{'bug_id'}} == CONTROLMAPMANDATORY) { + my $bug_id = $bug->{bug_id}; + if (my $involved_bug = $involved_bugs->{$bug_id}) { + $bug->{last_visit_status} = $involved_bug->{updated} ? 'updated' : 'up_to_date'; + } + elsif ($user->id) { + $bug->{last_visit_status} = $involved_new_bugs->{$bug_id} ? 'new' : 'unknown'; + } + next unless defined $min_membercontrol{$bug_id}; + if ($min_membercontrol{$bug_id} == CONTROLMAPMANDATORY) { $bug->{'secure_mode'} = 'implied'; } else { diff --git a/docs/en/rst/administering/keywords.rst b/docs/en/rst/administering/keywords.rst index 245bcbe4c..d61a5aea5 100644 --- a/docs/en/rst/administering/keywords.rst +++ b/docs/en/rst/administering/keywords.rst @@ -10,7 +10,5 @@ must be fixed by the next release—this keyword can make tracking those bugs much easier. Keywords are global, rather than per product. Keywords can be created, edited, or deleted by clicking the "Keywords" -link in the admin page. There are two fields for each keyword—the keyword -itself and a brief description. Currently keywords cannot be marked obsolete -to prevent future usage. - +link in the admin page. There are three fields for each keyword—the keyword +itself, a brief description, and if the keyword is active or not. diff --git a/editkeywords.cgi b/editkeywords.cgi index 01f30dbed..e6b62bec3 100755 --- a/editkeywords.cgi +++ b/editkeywords.cgi @@ -110,6 +110,7 @@ if ($action eq 'update') { $keyword->set_all({ name => scalar $cgi->param('name'), description => scalar $cgi->param('description'), + is_active => scalar $cgi->param('is_active'), }); my $changes = $keyword->update(); diff --git a/extensions/Mageia/Config.pm b/extensions/Mageia/Config.pm new file mode 100644 index 000000000..ce0eae39d --- /dev/null +++ b/extensions/Mageia/Config.pm @@ -0,0 +1,22 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +package Bugzilla::Extension::Mageia; + +use 5.10.1; +use strict; +use warnings; + +use constant NAME => 'Mageia'; + +use constant REQUIRED_MODULES => [ +]; + +use constant OPTIONAL_MODULES => [ +]; + +__PACKAGE__->NAME; diff --git a/extensions/Mageia/Extension.pm b/extensions/Mageia/Extension.pm new file mode 100644 index 000000000..982a3bdb7 --- /dev/null +++ b/extensions/Mageia/Extension.pm @@ -0,0 +1,186 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +package Bugzilla::Extension::Mageia; + +use 5.10.1; +use strict; +use warnings; + +use parent qw(Bugzilla::Extension); + +use Bugzilla::Constants qw(EVT_CC REL_GLOBAL_WATCHER); +use Bugzilla::Bug qw(LogActivityEntry); +use Bugzilla::Field qw(get_field_id); +use Bugzilla::User qw(); +use Bugzilla::User::Setting qw(add_setting); +use Bugzilla::Extension::Mageia::Util qw(compare_datetimes); + +use Email::Address; +use Encode qw(encode); + +# Let's match the Bugzilla version it's written for. +our $VERSION = '5.0'; + +# sysadmin-bugs@ml.mageia.org user ID = 175. +use constant SYSADMIN_USER_ID => 175; + +use constant MGA_SETTINGS => { + mga_inline_history => { options => ['on', 'off'], default => 'on' }, +}; + +sub bug_end_of_create_validators { + my ($self, $args) = @_; + + # If a user enters 'validated_update' as keyword, + # automatically CC sysadmin-bugs@ml.mageia.org. + my $keywords = $args->{params}->{keywords}; + + if (grep { $_->name eq 'validated_update' } @$keywords) { + my $cc_list = $args->{params}->{cc}; + if (!grep { $_ == SYSADMIN_USER_ID } @$cc_list) { + push(@$cc_list, SYSADMIN_USER_ID); + } + } +} + +sub bug_end_of_update { + my ($self, $args) = @_; + my $bug = $args->{bug}; + my $dbh = Bugzilla->dbh; + my $user = Bugzilla->user; + + my $new_keywords_str; + # Call exists to avoid autovivification of $args->{changes} if it does not exist. + # Else $bug->update() always sees the bug as being edited. + if (exists $args->{changes} && exists $args->{changes}->{keywords}) { + $new_keywords_str = $args->{changes}->{keywords}->[1]; + } + + # If a user enters 'validated_update' as keyword, automatically + # CC sysadmin-bugs@ml.mageia.org. + if ($new_keywords_str) { + my @new_keywords = split(/[,\s]+/, $new_keywords_str); + if (grep { $_ eq 'validated_update' } @new_keywords + and !grep { $_->id == SYSADMIN_USER_ID } @{$bug->cc_users}) + { + # Safer to clear the cache and let Bugzilla regenerate them if needed. + delete $bug->{cc_users}; + delete $bug->{cc}; + $dbh->do('INSERT INTO cc (bug_id, who) VALUES (?, ?)', + undef, ($bug->id, SYSADMIN_USER_ID)); + + # We also have to update the bug history to reflect this change. + my $changed_cc = $args->{changes}->{cc}; + my $sysadmin_login = Bugzilla::User->new(SYSADMIN_USER_ID)->login; + + if ($changed_cc->[1]) { + $changed_cc->[1] .= ", $sysadmin_login"; + } + else { + $changed_cc->[1] = $sysadmin_login; + } + + my $field_id = get_field_id('cc'); + $dbh->do('DELETE FROM bugs_activity + WHERE bug_id = ? AND bug_when = ? AND fieldid = ?', + undef, ($bug->id, $args->{timestamp}, $field_id)); + + LogActivityEntry($bug->id, 'cc', $changed_cc->[0] // '', $changed_cc->[1], + $user->id, $args->{timestamp}); + } + } +} + +sub bug_format_comment { + my ($self, $args) = @_; + my $regexes = $args->{'regexes'}; + # The Mageia DB was initially using SQL_ASCII as encoding (which means "no encoding"). + # The move to UTF8 caused some characters to be badly decoded, which we fix here. + # Convert "é" into "é". + push(@$regexes, { match => qr/\xc3\xa9/, replace => "\xe9" }); +} + +sub enter_bug_entrydefaultvars { + my ($self, $vars) = @_; + my $cgi = Bugzilla->cgi; + + # By default, users should get the guided form when reporting a new bug. + # Pass &normal=1 to the URL to get the official bug form. + my $format = $cgi->param('normal') ? '' : 'guided'; + $cgi->param('format', $format); +} + +sub install_before_final_checks { + # A hook in Bugzilla::Install::SETTINGS() would be much cleaner. :( + my %settings = %{MGA_SETTINGS()}; + foreach my $setting (keys %settings) { + add_setting($setting, $settings{$setting}->{options}, $settings{$setting}->{default}); + } +} + +sub mailer_before_send { + my ($self, $args) = @_; + my $email = $args->{email}; + + # Include the changer's name in the "From:" field. + if (my $changer = $email->header('X-Bugzilla-Who')) { + $changer = Bugzilla::User->new({ name => $changer }); + return unless $changer; + my $address = Email::Address->new($changer->name, $email->header('From')); + $email->header_set('From', encode('MIME-Header', $address->format)); + } +} + +sub template_before_process { + my ($self, $args) = @_; + _inline_history($args) if $args->{file} eq 'bug/comments.html.tmpl'; +} + +sub _inline_history { + my $args = shift; + my $user = Bugzilla->user; + return if $user->setting('mga_inline_history') eq 'off'; + # Only display the bug history in chronological order. + return if $user->setting('comment_sort_order') ne 'oldest_to_newest'; + + my $bug = $args->{vars}->{bug}; + my ($history) = $bug->get_activity(); + # Filter private comments that the user is not allowed to see. + my @comments = grep { !$_->is_private || $user->is_insider || $user->id == $_->author->id } @{ $bug->comments }; + my %h_times = map { $_->{when} => $_ } @$history; + my %c_times = map { $_->creation_ts => $_ } @comments; + my @all_times = sort { compare_datetimes($a, $b) } (keys %c_times, keys %h_times); + my $curr_comment; + + foreach my $time (@all_times) { + if ($c_times{$time}) { + $curr_comment = $c_times{$time}; + $curr_comment->{inline_history} //= []; + } + if (my $activity = $h_times{$time}) { + # If we have no visible comment to attach the activity to, then ignore it. + # This can happen if the initial comment (comment 0) is private. + next unless $curr_comment; + $activity->{after} = compare_datetimes($time, $curr_comment->creation_ts); + $activity->{who} = new Bugzilla::User({ name => $activity->{who}, cache => 1 }); + push(@{ $curr_comment->{inline_history} }, $activity); + } + } +} + +sub user_wants_mail { + my ($self, $args) = @_; + return unless $args->{relationship} == REL_GLOBAL_WATCHER; + + my $wants_mail = $args->{wants_mail}; + my @events = @{ $args->{events} }; + # Do not email global watchers if the single change is about the CC list. + $$wants_mail = (scalar(@events) == 1 && $events[0] == EVT_CC) ? 0 : 1; +} + +__PACKAGE__->NAME; diff --git a/extensions/Mageia/lib/Util.pm b/extensions/Mageia/lib/Util.pm new file mode 100644 index 000000000..60447fa28 --- /dev/null +++ b/extensions/Mageia/lib/Util.pm @@ -0,0 +1,44 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +package Bugzilla::Extension::Mageia::Util; + +use 5.10.1; +use strict; +use warnings; + +use parent qw(Exporter); + +our @EXPORT = qw(compare_datetimes); + +# This file can be loaded by your extension via +# "use Bugzilla::Extension::Mageia::Util". You can put functions +# used by your extension in here. (Make sure you also list them in +# @EXPORT.) + +# Return -1 if $t1 < $t2, 0 if $t1 == $t2, 1 if $t1 > $t2, undef if a date is invalid. +sub compare_datetimes { + my ($t1, $t2) = @_; + my (@time1, @time2); + if ($t1 =~ /^(\d{4})[\.-](\d{2})[\.-](\d{2})(?: (\d{2}):(\d{2}):(\d{2}))?$/) { + @time1 = ($1, $2, $3, $4, $5, $6); + } + if ($t2 =~ /^(\d{4})[\.-](\d{2})[\.-](\d{2})(?: (\d{2}):(\d{2}):(\d{2}))?$/) { + @time2 = ($1, $2, $3, $4, $5, $6); + } + return undef unless scalar(@time1) && scalar(@time2); + + for my $i (0..5) { + $t1 = $time1[$i] // 0; + $t2 = $time2[$i] // 0; + next if $t1 == $t2; + return $t1 <=> $t2; + } + return 0; +} + +1; diff --git a/extensions/Mageia/template/en/default/bug/create/comment-guided.txt.tmpl b/extensions/Mageia/template/en/default/bug/create/comment-guided.txt.tmpl new file mode 100644 index 000000000..7b5018e6d --- /dev/null +++ b/extensions/Mageia/template/en/default/bug/create/comment-guided.txt.tmpl @@ -0,0 +1,10 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +[% USE Bugzilla %] +[% Bugzilla.cgi.param("comment") %] diff --git a/extensions/Mageia/template/en/default/bug/create/create-guided.html.tmpl b/extensions/Mageia/template/en/default/bug/create/create-guided.html.tmpl new file mode 100644 index 000000000..7f0f22ac8 --- /dev/null +++ b/extensions/Mageia/template/en/default/bug/create/create-guided.html.tmpl @@ -0,0 +1,300 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +[%# INTERFACE: + # This template has the same interface as create.html.tmpl + #%] + +[% USE Bugzilla %] +[% cgi = Bugzilla.cgi %] + +[% PROCESS global/header.html.tmpl + title = "Enter $terms.ABug" + onload = "PutDescription()" + style_urls = ['skins/standard/bug.css'] + javascript_urls = ['js/util.js', 'js/field.js'] + yui = ['autocomplete'] + %] + +[% defaultcontent = "Description of problem:\n\n\n" _ + "Version-Release number of selected component (if applicable):\n\n\n" _ + "How reproducible:\n\n\nSteps to Reproduce:\n1.\n2.\n3.\n" %] + +[%# This script displays the descriptions for selected components. %] +<script type="text/javascript"> +var descriptions = [ +[% FOREACH c = product.components %] + [% NEXT IF NOT c.is_active %] + '[% c.description FILTER js %]', +[% END %] +]; + +function PutDescription() { + var description = document.getElementById('description'); + var componentIndex = document.getElementById('component').selectedIndex; + YAHOO.util.Dom.removeClass("description", "bz_default_hidden"); + if (componentIndex != -1) { + description.innerHTML = descriptions[componentIndex]; + } +} + +function CheckDetails(e) { + if (e.form.comment.value == '[% defaultcontent FILTER js FILTER html %]') { + alert('Please enter some details about this [% terms.bug %].'); + e.form.comment.focus(); + return false; + } + return true; +} +</script> + +<p> + Submit [% terms.abug %] using the + <a href="enter_bug.cgi?product=[% product.name FILTER html %]&normal=1">expert [% terms.bug %] form</a>. +</p> + +<form id="guided_form" method="post" action="post_bug.cgi"> + <input type="hidden" name="format" value="guided"> + <input type="hidden" name="priority" value="[% default.priority FILTER html %]"> + <input type="hidden" name="token" value="[% token FILTER html %]"> + +<table> + <tr> + [% INCLUDE "bug/field-label.html.tmpl" field = bug_fields.product %] + <td> + <input type="hidden" name="product" value="[% product.name FILTER html %]"> + [% product.name FILTER html %] + </td> + </tr> + + <tr> + [% INCLUDE "bug/field-label.html.tmpl" field = bug_fields.component editable = 1 %] + <td> + <select name="component" id="component" size="5" onchange="PutDescription()" + aria-required="true" class="required" required> + [% IF NOT default.component_ %] + [% default.component_ = "RPM Packages" %] + [% END %] + [% FOREACH c = product.components %] + [% NEXT IF NOT c.is_active %] + <option value="[% c.name FILTER html %]" + [%+ 'selected="selected"' IF c.name == default.component_ %]> + [% c.name FILTER html %] + </option> + [% END %] + </select> + + <div id="description" class="comment bz_default_hidden"> + Select a component to see its description here. + </div> + + <p> + The area where the problem occurs. + To pick the right component, you could use the same one as + similar [% terms.bugs %] you found in your search, or read the full list of + <a href="describecomponents.cgi?product=[% product.name FILTER uri %]" + target="_blank" >component descriptions</a> (opens in new window) if + you need more help. + </p> + </td> + </tr> + + <tr> + [% INCLUDE "bug/field-label.html.tmpl" field = bug_fields.version editable = 1 %] + <td> + <select name="version" id="version" size="5" aria-required="true" class="required" required> + [% FOREACH v = version %] + [% NEXT IF NOT v.is_active %] + <option value="[% v.name FILTER html %]" + [% ' selected="selected"' IF v.name == default.version %]>[% v.name FILTER html -%] + </option> + [% END %] + </select> + + <p> + The version in which the problem occurs. + </p> + </td> + </tr> + + <tr> + [% INCLUDE bug/field.html.tmpl + bug = default, field = bug_fields.rep_platform, editable = 1, + value = default.rep_platform %] + </tr> + + <tr> + [% INCLUDE "bug/field-label.html.tmpl" field = bug_fields.cf_rpmpkg editable = 1 %] + <td> + <input size="80" name="cf_rpmpkg" id="cf_rpmpkg"> + <p> + This is where you can identify exactly which RPM package is involved in + this [% terms.bug %] report. For instance, if you know the problem you + are having is with the program <tt>mysqld</tt>, then execute + <tt>rpm -qif /usr/sbin/mysqld</tt>. This will tell you the name and version + of the RPM package (i.e. mariadb-core-10.1.24-1.mga6) as well as other + information. In particular, you are looking for the "Source RPM" field + (i.e. mariadb-10.1.24-1.mga6.src.rpm) -- this is the information you should + provide here. Alternatively, you may use + <tt>rpm -qf /usr/sbin/mysqld --qf '%{SOURCERPM}\n'</tt> to obtain the + information. If you do not know the location of the program in question, + use <tt>rpm -qif `which mysqld`</tt>. Please enter that information above. + </p> + </td> + </tr> + + <tr> + [% INCLUDE "bug/field-label.html.tmpl" field = bug_fields.bug_file_loc editable = 1 %] + <td> + <input size="80" name="bug_file_loc" placeholder="https://"> + <p> + URL that demonstrates the problem you are submitting (optional). + </p> + </td> + </tr> + + <tr> + [% INCLUDE "bug/field-label.html.tmpl" field = bug_fields.short_desc editable = 1 %] + <td> + <input size="80" name="short_desc" id="short_desc" maxlength="255" + spellcheck="true" aria-required="true" class="required" required> + <p> + A sentence which summarizes the problem. + Please be descriptive and use lots of keywords. + </p> + <p> + <kbd> + <span class="bad">Bad example</span>: mail crashed + </kbd> + <br> + <kbd> + <span class="good">Good example</span>: + crash in Evolution while checking for new POP mail + </kbd> + </p> + </td> + </tr> + + <tr> + <th id="field_label_details" class="field_label required">Details</th> + <td> + [% INCLUDE global/textarea.html.tmpl + id = 'comment' + name = 'comment' + minrows = 13 + cols = constants.COMMENT_COLS + mandatory = 1 + defaultcontent = defaultcontent + %] + + [% IF user.is_insider %] + <br> + <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"> + Initial description is private (visible only to members + of the <strong>[% Param('insidergroup') FILTER html %]</strong> group) + </label> + <script> + updateCommentTagControl(document.getElementById('comment_is_private'), 'comment'); + </script> + [% END %] + <p> + Expand on the Summary. Please be as specific as possible about what is wrong. + </p> + <p> + <kbd> + <span class="bad">Bad example</span>: I can't seem to login to the system. Please help! + </kbd> + <br> + <kbd> + <span class="good">Good example</span>: Description of problem: + <br><br> + I'm unable to login to the system via ssh. The /var/log/messages log + indicates there is a problem with the pam module pam_ldap, but the + /etc/pam.d/system-auth file doesn't contain that module and I'm not + using LDAP. I looked at /etc/pam.d/sshd and it does contain that module + but I'm not sure how it got there, unless it was due to the super-spiffy + super-ldap-mojo package I installed yesterday. + <br><br> + Version-Release number of selected component (if applicable): + <br><br> + openldap-2.4.40-3.1.mga5, pam-1.1.8-10.1.mga5 + <br><br> + How reproducible: + <br><br> + Every time I attempt to login. + <br><br> + Steps to Reproduce:<br> + 1. ssh user@host<br> + 2. see the rejection + </kbd> + </p> + </td> + </tr> + + <tr> + [% INCLUDE "bug/field-label.html.tmpl" field = bug_fields.bug_severity editable = 1 %] + <td> + <select name="bug_severity"> + <option name="critical" value="critical"> + Critical: The software crashes, hangs, or causes you to + lose data. + </option> + <option name="major" value="major"> + Major: A major feature is broken. + </option> + <option name="normal" value="normal" selected="selected"> + Normal: It's [% terms.abug %] that should be fixed. + </option> + <option name="minor" value="minor"> + Minor: Minor loss of function, and there's an easy workaround. + </option> + <option name="enhancement" value="enhancement"> + Enhancement: Request for new feature or enhancement. + </option> + </select> + <p> + Indicate how serious the problem is, or if your [% terms.bug %] is a + request for a new feature. + </p> + </td> + </tr> + + <tr> + [% INCLUDE "bug/field-label.html.tmpl" field = bug_fields.assigned_to editable = 1 %] + <td> + [% INCLUDE global/userselect.html.tmpl + id => "assigned_to" + name => "assigned_to" + value => assigned_to + disabled => assigned_to_disabled + size => 30 + emptyok => 1 + %] + <p>Leave blank to assign to the default component owner.</p> + </td> + </tr> + + [% Hook.process('form') %] +</table> + +<p> + <input type="submit" id="report" value="Submit [% terms.Bug %] Report" + onclick="var res = CheckDetails(this); return res"> +</p> + +<p> + That's it! Thanks very much. You'll be notified by email about any progress + that is made on fixing your [% terms.bug %]. Thank you for choosing Mageia! +</p> + +</form> + +[% PROCESS global/footer.html.tmpl %] diff --git a/extensions/Mageia/template/en/default/global/banner.html.tmpl b/extensions/Mageia/template/en/default/global/banner.html.tmpl new file mode 100644 index 000000000..76f1d123e --- /dev/null +++ b/extensions/Mageia/template/en/default/global/banner.html.tmpl @@ -0,0 +1,11 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +<script src="https://nav.mageia.org/js/" type="text/javascript"></script> + +<div id="banner"></div> diff --git a/extensions/Mageia/template/en/default/hook/README b/extensions/Mageia/template/en/default/hook/README new file mode 100644 index 000000000..e6c4add58 --- /dev/null +++ b/extensions/Mageia/template/en/default/hook/README @@ -0,0 +1,5 @@ +Template hooks go in this directory. Template hooks are called in normal +Bugzilla templates like [% Hook.process('some-hook') %]. +More information about them can be found in the documentation of +Bugzilla::Extension. (Do "perldoc Bugzilla::Extension" from the main +Bugzilla directory to see that documentation.)
\ No newline at end of file diff --git a/extensions/Mageia/template/en/default/hook/account/auth/login-small-additional_methods.html.tmpl b/extensions/Mageia/template/en/default/hook/account/auth/login-small-additional_methods.html.tmpl new file mode 100644 index 000000000..675af49f1 --- /dev/null +++ b/extensions/Mageia/template/en/default/hook/account/auth/login-small-additional_methods.html.tmpl @@ -0,0 +1,23 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +[% UNLESS user.id %] + [% UNLESS Param('createemailregexp') AND user.authorizer.user_can_create_account %] + <li id="new_account_container[% qs_suffix FILTER html %]"> + <span class="separator">| </span> + <a href="https://identity.mageia.org/register">New Account</a> + </li> + [% END %] + + [% UNLESS user.authorizer.can_change_password %] + <li id="forgot_container[% qs_suffix FILTER html %]"> + <span class="separator">| </span> + <a href="https://identity.mageia.org/forgot_password">Forgot Password</a> + </li> + [% END %] +[% END %] diff --git a/extensions/Mageia/template/en/default/hook/account/prefs/account-field.html.tmpl b/extensions/Mageia/template/en/default/hook/account/prefs/account-field.html.tmpl new file mode 100644 index 000000000..700f06a69 --- /dev/null +++ b/extensions/Mageia/template/en/default/hook/account/prefs/account-field.html.tmpl @@ -0,0 +1,10 @@ +[% IF Param('user_verify_class') == "LDAP" %] + <tr> + <th></th> + <td>(Changes will be undone when you log out. Use the link below for permanent changes.)</td> + </tr> + <tr> + <th>Edit account (email address, password, real name):</th> + <td><a href="https://identity.mageia.org" target="_blank">Visit identity.mageia.org</a></td> + </tr> +[% END %] diff --git a/extensions/Mageia/template/en/default/hook/bug/comments-a_comment-end.html.tmpl b/extensions/Mageia/template/en/default/hook/bug/comments-a_comment-end.html.tmpl new file mode 100644 index 000000000..cbe11b4ca --- /dev/null +++ b/extensions/Mageia/template/en/default/hook/bug/comments-a_comment-end.html.tmpl @@ -0,0 +1,76 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +[% RETURN IF user.setting('mga_inline_history') == 'off' %] + +[% FOREACH activity = comment.inline_history %] + [% IF activity.after %] + </div> + <div class="bz_comment bz_inline_history"> + <div class="bz_comment_head"> + <span class="bz_comment_user"> + [%# No need to recreate the exact same template if we already have it. %] + [% who_id = activity.who.id %] + [% UNLESS user_cache.$who_id %] + [% user_cache.$who_id = BLOCK %] + [% INCLUDE global/user.html.tmpl who = activity.who %] + [% END %] + [% END %] + [% user_cache.$who_id FILTER none %] + </span> + + <span class="bz_comment_user_images"> + [% FOREACH group = activity.who.groups_with_icon %] + <img src="[% group.icon_url FILTER html %]" + alt="[% group.name FILTER html %]" + title="[% group.name FILTER html %] - [% group.description FILTER html %]"> + [% END %] + </span> + + <span class="bz_comment_time"> + [%+ activity.when FILTER time %] + </span> + </div> + [% ELSE %] + <hr> + [% END %] + + <p class="bz_inline_history"> + [% FOREACH change = activity.changes %] + [% IF change.attachid AND field_descs.${change.fieldname}.match('^Attachment') %] + <a href="attachment.cgi?id=[% change.attachid FILTER html %]&action=edit"> + [% field_descs.${change.fieldname}.replace('^Attachment', "Attachment ${change.attachid}</a>") FILTER none %]: + [% ELSIF activity.comment_id AND field_descs.${change.fieldname}.match('^Comment') %] + [% comment_num = change.comment.count %] + <a href="show_bug.cgi?id=[% bug.id FILTER html %]#c[% comment_num FILTER html %]" + onclick="document.getElementById('c[% comment_num FILTER html %]').classList.add('bz_comment_hilite')"> + [% field_descs.${change.fieldname}.replace('^Comment', "Comment $comment_num</a>") FILTER none %]: + [% ELSE %] + [% field_descs.${change.fieldname} FILTER html %]: + [% END %] + <span class="change_removed">[% PROCESS format_field_value value = change.removed %]</span> => + <span class="change_added">[% PROCESS format_field_value value = change.added %]</span><br> + [% END %] + </p> +[% END %] + +[% BLOCK format_field_value %] + [% IF value.length %] + [% IF 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 html %] + [% ELSE %] + [% display_value(change.fieldname, value) FILTER html FILTER html_line_break %] + [% END %] + [% ELSE %] + (none) + [% END %] +[% END %] diff --git a/extensions/Mageia/template/en/default/hook/global/header-start.html.tmpl b/extensions/Mageia/template/en/default/hook/global/header-start.html.tmpl new file mode 100644 index 000000000..01fab7fab --- /dev/null +++ b/extensions/Mageia/template/en/default/hook/global/header-start.html.tmpl @@ -0,0 +1,10 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +[% favicon_url = "https://www.mageia.org/g/favicon.png" %] +[% style_urls.push("extensions/Mageia/web/style.css") %] diff --git a/extensions/Mageia/template/en/default/hook/global/setting-descs-settings.none.tmpl b/extensions/Mageia/template/en/default/hook/global/setting-descs-settings.none.tmpl new file mode 100644 index 000000000..5b1da08aa --- /dev/null +++ b/extensions/Mageia/template/en/default/hook/global/setting-descs-settings.none.tmpl @@ -0,0 +1,9 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +[% setting_descs.mga_inline_history = "Display inline history in $terms.bug reports" %] diff --git a/extensions/Mageia/template/en/default/hook/global/variables-end.none.tmpl b/extensions/Mageia/template/en/default/hook/global/variables-end.none.tmpl new file mode 100644 index 000000000..4f651a5ae --- /dev/null +++ b/extensions/Mageia/template/en/default/hook/global/variables-end.none.tmpl @@ -0,0 +1,9 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +[% terms.Bugzilla = "Mageia Bugzilla" %] diff --git a/extensions/Mageia/template/en/default/hook/index-additional_links.html.tmpl b/extensions/Mageia/template/en/default/hook/index-additional_links.html.tmpl new file mode 100644 index 000000000..3c2585887 --- /dev/null +++ b/extensions/Mageia/template/en/default/hook/index-additional_links.html.tmpl @@ -0,0 +1,14 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +[% UNLESS user.id %] + <p id="create_account"> + Don't have an account on [% terms.Bugzilla %]? + <a href="https://identity.mageia.org/register">Create one</a>. + </p> +[% END %] diff --git a/extensions/Mageia/template/en/default/mageia/README b/extensions/Mageia/template/en/default/mageia/README new file mode 100644 index 000000000..099d1a41a --- /dev/null +++ b/extensions/Mageia/template/en/default/mageia/README @@ -0,0 +1,16 @@ +Normal templates go in this directory. You can load them in your +code like this: + +use Bugzilla::Error; +my $template = Bugzilla->template; +$template->process('mageia/some-template.html.tmpl') + or ThrowTemplateError($template->error()); + +That would be how to load a file called some-template.html.tmpl that +was in this directory. + +Note that you have to be careful that the full path of your template +never conflicts with a template that exists in Bugzilla or in +another extension, or your template might override that template. That's why +we created this directory called 'mageia' for you, so you +can put your templates in here to help avoid conflicts.
\ No newline at end of file diff --git a/extensions/Mageia/web/README b/extensions/Mageia/web/README new file mode 100644 index 000000000..c3c41862f --- /dev/null +++ b/extensions/Mageia/web/README @@ -0,0 +1,7 @@ +Web-accessible files, like JavaScript, CSS, and images go in this +directory. You can reference them directly in your HTML. For example, +if you have a file called "style.css" and your extension is called +"Mageia", you would put it in "extensions/Mageia/web/style.css", and then +you could link to it in HTML like: + +<link href="extensions/Mageia/web/style.css" rel="stylesheet" type="text/css"> diff --git a/extensions/Mageia/web/style.css b/extensions/Mageia/web/style.css new file mode 100644 index 000000000..daffc088a --- /dev/null +++ b/extensions/Mageia/web/style.css @@ -0,0 +1,52 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This Source Code Form is "Incompatible With Secondary Licenses", as + * defined by the Mozilla Public License, v. 2.0. + */ + +body { + margin: 0; + padding-top: 0; + background-color: #fff !important; +} + +#create_account { + border: solid 1px; + background-color: #ffd386; + color: #9b1a1a; + padding: 1em; + text-align: center; + max-width: 30em; + margin: 1em auto; +} + +#guided_form { + padding: 1em; +} + +#guided_form .field_label { + white-space: nowrap; +} + +.bz_inline_history { + font-style: italic; + background-color: #fff !important; +} + +div.bz_comment_hilite { + border: solid 3px; +} + +.bz_comment_hilite pre { + background-color: inherit; +} + +.change_removed { + color: darkred; +} + +.change_added { + color: darkgreen; +} diff --git a/extensions/MoreBugUrl/Extension.pm b/extensions/MoreBugUrl/Extension.pm index 18507f8d1..0a4223e19 100644 --- a/extensions/MoreBugUrl/Extension.pm +++ b/extensions/MoreBugUrl/Extension.pm @@ -22,6 +22,7 @@ use constant MORE_SUB_CLASSES => qw( Bugzilla::Extension::MoreBugUrl::PHP Bugzilla::Extension::MoreBugUrl::Redmine Bugzilla::Extension::MoreBugUrl::Savane + Bugzilla::Extension::MoreBugUrl::Phabricator ); # We need to update bug_see_also table because both diff --git a/extensions/MoreBugUrl/disabled b/extensions/MoreBugUrl/disabled deleted file mode 100644 index e69de29bb..000000000 --- a/extensions/MoreBugUrl/disabled +++ /dev/null diff --git a/extensions/MoreBugUrl/lib/Phabricator.pm b/extensions/MoreBugUrl/lib/Phabricator.pm new file mode 100644 index 000000000..818d9af8f --- /dev/null +++ b/extensions/MoreBugUrl/lib/Phabricator.pm @@ -0,0 +1,41 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +package Bugzilla::Extension::MoreBugUrl::Phabricator; + +use 5.10.1; +use strict; +use warnings; + +use parent qw(Bugzilla::BugUrl); + +############################### +#### Methods #### +############################### + +sub should_handle { + my ($class, $uri) = @_; + return ($uri->path =~ m|^/T\d+$|) ? 1 : 0; +} + +sub _check_value { + my $class = shift; + + my $uri = $class->SUPER::_check_value(@_); + + # Phabricator URLs have only one form: + # http://example.com/T111 + + # Make sure there are no query parameters. + $uri->query(undef); + # And remove any # part if there is one. + $uri->fragment(undef); + + return $uri; +} + +1; diff --git a/extensions/MoreBugUrl/template/en/default/hook/global/user-error-bug_url_invalid_tracker.html.tmpl b/extensions/MoreBugUrl/template/en/default/hook/global/user-error-bug_url_invalid_tracker.html.tmpl index 7e544ef21..2ac6f89a5 100644 --- a/extensions/MoreBugUrl/template/en/default/hook/global/user-error-bug_url_invalid_tracker.html.tmpl +++ b/extensions/MoreBugUrl/template/en/default/hook/global/user-error-bug_url_invalid_tracker.html.tmpl @@ -14,3 +14,4 @@ <li>A b[% %]ug on b[% %]ugs.php.net.</li> <li>An issue in a Redmine installation.</li> <li>A b[% %]ug in a Savane installation.</li> +<li>A task in a Phabricator installation.</li> diff --git a/skins/standard/buglist.css b/skins/standard/buglist.css index e58baabfd..bebc4b465 100644 --- a/skins/standard/buglist.css +++ b/skins/standard/buglist.css @@ -118,6 +118,45 @@ tr.bz_secure_mode_implied td.first-child { tr.bz_secure_mode_manual td.first-child { } +div.bz_last_visit_description { + padding: 1em 0; +} +div.bz_last_visit_description span { + padding-left: 1em; + white-space: nowrap; +} +tr.bz_new_since_last_visit td.first-child:before, +span.bz_new_since_last_visit:before { + color: #ed2; + content: "\25CF"; + font-size: large; +} +tr.bz_updated_since_last_visit td.first-child:before, +span.bz_updated_since_last_visit:before { + color: #c00; + content: "\25CF"; + font-size: large; +} +tr.bz_up_to_date_since_last_visit td.first-child:before, +span.bz_up_to_date_since_last_visit:before { + color: #0c0; + content: "\25CF"; + font-size: large; +} +tr.bz_unknown_since_last_visit td.first-child:before, +span.bz_unknown_since_last_visit:before { + color: #aaa; + content: "\25CF"; + font-size: large; +} +/* Prevent wrapping of the colored disk besides the bug ID. */ +tr.bz_new_since_last_visit td.first-child, +tr.bz_updated_since_last_visit td.first-child, +tr.bz_up_to_date_since_last_visit td.first-child, +tr.bz_unknown_since_last_visit td.first-child { + white-space: nowrap; +} + td.bz_estimated_time_column, td.bz_remaining_time_column, td.bz_actual_time_column, diff --git a/t/010dependencies.t b/t/010dependencies.t index afd29a652..f565554d8 100644 --- a/t/010dependencies.t +++ b/t/010dependencies.t @@ -69,7 +69,7 @@ foreach my $module (keys %mods) { $used =~ s#/#::#g; $used =~ s#\.pm$##; $used =~ s#\$module#[^:]+#; - $used =~ s#\${[^}]+}#[^:]+#; + $used =~ s#\$\{[^}]+}#[^:]+#; $used =~ s#[" ]##g; push(@use, grep(/^\Q$used\E$/, keys %mods)); } diff --git a/template/en/default/admin/keywords/edit.html.tmpl b/template/en/default/admin/keywords/edit.html.tmpl index 23158d36f..7e6617a84 100644 --- a/template/en/default/admin/keywords/edit.html.tmpl +++ b/template/en/default/admin/keywords/edit.html.tmpl @@ -18,14 +18,19 @@ <form method="post" action="editkeywords.cgi"> <table id="admin_table_edit"> <tr> - <th>Name:</th> - <td><input size="64" maxlength="64" name="name" + <th><label for="name">Name:</label></th> + <td><input size="64" maxlength="64" name="name" id="name" value="[% keyword.name FILTER html %]" required></td> </tr> <tr> - <th>Description:</th> + <th><label for="is_active">Enabled For [% terms.Bugs %]</label></th> + <td><input id="is_active" name="is_active" type="checkbox" [% "checked" IF keyword.is_active %]></td> + </tr> + <tr> + <th><label for="decription">Description:</label></th> <td> [% INCLUDE global/textarea.html.tmpl + id = 'description' name = 'description' minrows = 4 cols = 64 diff --git a/template/en/default/admin/keywords/list.html.tmpl b/template/en/default/admin/keywords/list.html.tmpl index c3f4a5292..9d920036e 100644 --- a/template/en/default/admin/keywords/list.html.tmpl +++ b/template/en/default/admin/keywords/list.html.tmpl @@ -10,6 +10,7 @@ # keywords: array keyword objects having the properties: # - id: number. The ID of the keyword. # - name: string. The name of the keyword. + # - is_active: boolean. true if the keyword can be used. # - description: string. The description of the keyword. # - bug_count: number. The number of bugs with the keyword. #%] @@ -20,34 +21,39 @@ %] [% columns = [ - { - name => "name" - heading => "Edit keyword..." - contentlink => "editkeywords.cgi?action=edit&id=%%id%%" - }, - { - name => "description" - heading => "Description" - allow_html_content => 1 - }, - { - name => "bug_count" - heading => "$terms.Bugs" - class => "right" - contentlink => "buglist.cgi?keywords=%%name%%" - }, - { - heading => "Action" - content => "Delete" - contentlink => "editkeywords.cgi?action=del&id=%%id%%" - } - ] + { + name => "name" + heading => "Edit keyword..." + contentlink => "editkeywords.cgi?action=edit&id=%%id%%" + }, + { + name => "description" + heading => "Description" + allow_html_content => 1 + }, + { + name => "is_active", + heading => "Active", + yesno_field => 1 + }, + { + name => "bug_count" + heading => "$terms.Bugs" + class => "right" + contentlink => "buglist.cgi?keywords=%%name%%" + }, + { + heading => "Action" + content => "Delete" + contentlink => "editkeywords.cgi?action=del&id=%%id%%" + } +] %] [% PROCESS admin/table.html.tmpl - columns = columns - data = keywords - footer = footer_row + columns = columns + data = keywords + footer = footer_row %] <p><a href="editkeywords.cgi?action=add">Add a new keyword</a></p> diff --git a/template/en/default/attachment/edit.html.tmpl b/template/en/default/attachment/edit.html.tmpl index 184cdde05..570b611b2 100644 --- a/template/en/default/attachment/edit.html.tmpl +++ b/template/en/default/attachment/edit.html.tmpl @@ -188,9 +188,12 @@ [% END %] </a> </p> - [% ELSIF attachment.contenttype == "text/html" %] + [% ELSIF attachment.contenttype.match('^text/') %] [%# For security reasons (clickjacking, embedded scripts), we never - # render HTML pages from here. The source code is displayed instead. %] + # render HTML, XML or SVG pages directly. The source code for all + # text/* MIME types is displayed instead. If someone tries to abuse + # Bugzilla by manually editing the MIME type, it will be caught + # by the iframe below, thanks to its 'sandbox' attribute. %] [% INCLUDE global/textarea.html.tmpl id = 'viewFrame' minrows = 10 @@ -199,6 +202,8 @@ readonly = 'readonly' %] [% ELSE %] + [%# The 'sandbox' attribute causes all scripts and form submissions + # embedded in the attachment to be disabled, for security reasons. %] <iframe id="viewFrame" src="attachment.cgi?id=[% attachment.id %]" sandbox> <b>You cannot view the attachment while viewing its details because your browser does not support IFRAMEs. <a href="attachment.cgi?id=[% attachment.id %]">View the attachment on a separate page</a>.</b> diff --git a/template/en/default/bug/create/create.html.tmpl b/template/en/default/bug/create/create.html.tmpl index 61faf1c1a..d76c082cc 100644 --- a/template/en/default/bug/create/create.html.tmpl +++ b/template/en/default/bug/create/create.html.tmpl @@ -537,7 +537,7 @@ TUI_hide_default('attachment_text_field'); <tr> [% INCLUDE bug/field.html.tmpl bug = default, field = bug_fields.keywords, editable = 1, - value = keywords, possible_values = all_keywords, + value = keywords, possible_values = active_keywords, desc_url = "describekeywords.cgi", value_span = 3 %] </tr> diff --git a/template/en/default/bug/edit.html.tmpl b/template/en/default/bug/edit.html.tmpl index b8abe6bc5..e269d438d 100644 --- a/template/en/default/bug/edit.html.tmpl +++ b/template/en/default/bug/edit.html.tmpl @@ -329,20 +329,25 @@ [%# Importance (priority and severity) #%] [%###############################################################%] <tr> - <th class="field_label"> - [% can_edit_priority = bug.check_can_change_field('priority', 0, 1) %] - <label [% IF can_edit_priority %]for="priority"[% END %] accesskey="i"> - <a href="page.cgi?id=fields.html#importance"><u>I</u>mportance</a></label>: - </th> - <td> - [% INCLUDE bug/field.html.tmpl + [% can_edit_priority = bug.check_can_change_field('priority', 0, 1) %] + [% INCLUDE "bug/field-label.html.tmpl" + field = bug_fields.priority + editable = can_edit_priority + %] + <td class="field_value"> + [% INCLUDE bug/field.html.tmpl bug = bug, field = bug_fields.priority, no_tds = 1, value = bug.priority editable = can_edit_priority %] - [%+ INCLUDE bug/field.html.tmpl + + [% can_edit_severity = bug.check_can_change_field('bug_severity', 0, 1) %] + <label [% IF can_edit_severity %]for="bug_severity"[% END %] class="field_label"> + <a href="page.cgi?id=fields.html#bug_severity" class="field_help_link" + title="[% help_html.bug_severity FILTER txt FILTER collapse FILTER html %]">Severity</a>:</label> + [%+ INCLUDE bug/field.html.tmpl bug = bug, field = bug_fields.bug_severity, no_tds = 1, value = bug.bug_severity - editable = bug.check_can_change_field('bug_severity', 0, 1) %] + editable = can_edit_severity %] [% Hook.process('after_importance', 'bug/edit.html.tmpl') %] </td> </tr> @@ -544,7 +549,7 @@ [% INCLUDE bug/field.html.tmpl bug = bug, field = bug_fields.keywords, value = bug.keywords editable = bug.check_can_change_field("keywords", 0, 1), - desc_url = "describekeywords.cgi", possible_values = all_keywords + desc_url = "describekeywords.cgi", possible_values = active_keywords %] </tr> [% END %] diff --git a/template/en/default/bug/navigate.html.tmpl b/template/en/default/bug/navigate.html.tmpl index b5e3ba7a2..8d2478479 100644 --- a/template/en/default/bug/navigate.html.tmpl +++ b/template/en/default/bug/navigate.html.tmpl @@ -15,7 +15,7 @@ <li> - <a href="show_bug.cgi?ctype=xml&id= [% bug.bug_id FILTER uri %]">XML</a></li> <li> - <a href="enter_bug.cgi?cloned_bug_id= - [% bug.bug_id FILTER uri %]">Clone This + [% bug.bug_id FILTER uri %]&normal=1">Clone This [% terms.Bug %]</a></li> [%# Links to more things users can do with this bug. %] [% Hook.process("links") %] diff --git a/template/en/default/email/bugmail.html.tmpl b/template/en/default/email/bugmail.html.tmpl index fd348a656..12c20d264 100644 --- a/template/en/default/email/bugmail.html.tmpl +++ b/template/en/default/email/bugmail.html.tmpl @@ -48,6 +48,10 @@ [% END %] <hr> + <span> + Do not reply by email to add a comment. Emails will be discarded.<br> + Use the link at the top of this email and log into [% terms.Bugzilla %] instead. + </span> <span>You are receiving this mail because:</span> <ul> diff --git a/template/en/default/email/bugmail.txt.tmpl b/template/en/default/email/bugmail.txt.tmpl index 1f04db7b1..336f40415 100644 --- a/template/en/default/email/bugmail.txt.tmpl +++ b/template/en/default/email/bugmail.txt.tmpl @@ -32,6 +32,9 @@ Referenced [% terms.Bugs %]: [% END %] [% END %] -- [%# Protect the trailing space of the signature marker %] +Do not reply by email to add a comment. Emails will be discarded. +Use the link at the top of this email and log into [% terms.Bugzilla %] instead. + You are receiving this mail because: [% SET reason_lines = [] %] [% FOREACH reason = reasons %] diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl index 69afaf46a..dcf4fc789 100644 --- a/template/en/default/global/user-error.html.tmpl +++ b/template/en/default/global/user-error.html.tmpl @@ -1433,7 +1433,7 @@ Either you mis-typed the name or that user has not yet registered for a [% terms.Bugzilla %] account. [% ELSIF class == "Bugzilla::Keyword" %] - See the list of available <a href="describekeywords.cgi">keywords</a>. + See the list of available <a href="describekeywords.cgi?show_inactive_keywords=1">keywords</a>. [% END %] [% ELSIF error == "old_password_incorrect" %] diff --git a/template/en/default/list/list.html.tmpl b/template/en/default/list/list.html.tmpl index 368cd9c08..321716873 100644 --- a/template/en/default/list/list.html.tmpl +++ b/template/en/default/list/list.html.tmpl @@ -131,6 +131,24 @@ [% END %] </li> [% END %] + +[% IF user.id AND bugs.size %] + <div class="bz_last_visit_description"> + <span class="bz_new_since_last_visit"> + [% terms.Bugs %] you are involved in, but which you never visited or did not visit + in the last [% Param('last_visit_keep_days') %] days + </span> + <span class="bz_updated_since_last_visit"> + [% terms.Bugs %] you are involved in, which have been updated since your last visit + </span> + <span class="bz_up_to_date_since_last_visit"> + [% terms.Bugs %] you are involved in, which got no updates since your last visit + </span> + <span class="bz_unknown_since_last_visit"> + [% terms.Bugs %] you are not involved in + </span> + </div> +[% END %] </ul> <hr> diff --git a/template/en/default/list/table.html.tmpl b/template/en/default/list/table.html.tmpl index d3abc9b21..f6ca804e8 100644 --- a/template/en/default/list/table.html.tmpl +++ b/template/en/default/list/table.html.tmpl @@ -168,6 +168,7 @@ [%+ "bz_$bug.resolution" FILTER css_class_quote IF bug.resolution -%] [%+ "bz_secure" IF bug.secure_mode -%] [%+ "bz_secure_mode_$bug.secure_mode" FILTER css_class_quote IF bug.secure_mode -%] + [%+ "bz_${bug.last_visit_status}_since_last_visit" FILTER css_class_quote IF bug.last_visit_status -%] [%+ count % 2 == 1 ? "bz_row_odd" : "bz_row_even" -%] "> diff --git a/template/en/default/reports/keywords.html.tmpl b/template/en/default/reports/keywords.html.tmpl index 598979d33..6e7ad0c50 100644 --- a/template/en/default/reports/keywords.html.tmpl +++ b/template/en/default/reports/keywords.html.tmpl @@ -18,36 +18,67 @@ title = "$terms.Bugzilla Keyword Descriptions" style_urls = ['skins/standard/admin.css'] %] +[% cgi = Bugzilla.cgi %] +[% show_inactive_keywords = cgi.param("show_inactive_keywords") %] -<table id="admin_table"> +<script> + $(document).ready(function () { + var show_inactive_keywords = [% show_inactive_keywords ? "true" : "false" FILTER none %]; + link = $("#keywords_show_hide"), + rows = $("tr.keyword_inactive"); + + link.click(function (event) { + if (show_inactive_keywords) { + show_inactive_keywords = false; + rows.show(); + link.html("Hide inactive keywords"); + } + else { + show_inactive_keywords = true; + rows.hide(); + link.html("Show inactive keywords"); + } + event.preventDefault(); + }).click(); + }); +</script> + +<p> + <a href="[% urlbase FILTER html %]?show_inactive_keywords=[% show_inactive_keywords ? "1" : "0" FILTER none %]" + id="keywords_show_hide">[% show_inactive_keywords ? "Show" : "Hide" FILTER html %] inactive keywords</a> +</p> + +<table id="admin_table" class="describe_keywords"> <tr class="column_header"> <th>Name</th> <th>Description</th> + <th>Active</th> <th>Open [% terms.Bugs %]</th> <th>Total [% terms.Bugs %]</th> </tr> [% FOREACH keyword = keywords %] - <tr id="[% keyword.name FILTER html %]"> - <td>[% keyword.name FILTER html %]</td> - <td>[% keyword.description FILTER html_light %]</td> - <td class="center"> - [% IF keyword.bug_count > 0 %] - <a href="buglist.cgi?keywords=[% keyword.name FILTER uri %]&resolution=---"> - Search</a> - [% ELSE %] - none - [% END %] - </td> - <td class="right"> - [% IF keyword.bug_count > 0 %] - <a href="buglist.cgi?keywords=[% keyword.name FILTER uri %]"> - [% keyword.bug_count %]</a> - [% ELSE %] - none - [% END %] - </td> - </tr> + <tr id="[% keyword.name FILTER html %]" class="[% keyword.is_active ? "keyword_active" : "keyword_inactive" FILTER html %]"> + <td>[% keyword.name FILTER html %]</td> + <td>[% keyword.description FILTER html_light %]</td> + <td>[% keyword.is_active ? "Yes" : "No" FILTER html %]</td> + <td class="center"> + [% IF keyword.bug_count > 0 %] + <a href="buglist.cgi?keywords=[% keyword.name FILTER uri %]&resolution=---"> + Search</a> + [% ELSE %] + none + [% END %] + </td> + <td class="right"> + [% IF keyword.bug_count > 0 %] + <a href="buglist.cgi?keywords=[% keyword.name FILTER uri %]"> + [% keyword.bug_count %]</a> + [% ELSE %] + none + [% END %] + </td> + </tr> [% END %] </table> |