Bug 70605 - Fix field caching

git-svn-id: svn://svn.office.custis.ru/3rdparty/bugzilla.org/trunk@1162 6955db30-a419-402b-8a0d-67ecbb4d7f56
master
vfilippov 2010-12-10 18:02:52 +00:00
parent 4820bfd388
commit 21f46cb467
18 changed files with 213 additions and 240 deletions

View File

@ -678,10 +678,20 @@ sub cache_fields
return $Bugzilla::CACHE_FIELDS;
}
sub COLUMNS { Bugzilla::Search->COLUMNS }
sub COLUMN_ALIASES { Bugzilla::Search->COLUMN_ALIASES }
sub rc_cache_fields
{
my $class = shift;
return ($class->request_cache->{cache_fields} ||= {});
}
sub refresh_cache_fields
{
my $class = shift;
delete $class->request_cache->{fields_delta_ts};
delete $class->request_cache->{cache_fields};
}
sub _fill_fields_cache
@ -689,9 +699,7 @@ sub _fill_fields_cache
my ($r) = @_;
if (!$r->{id})
{
my $f;
eval { $f = [ Bugzilla::Field->get_all ]; };
return undef if $@;
my $f = [ Bugzilla::Field->get_all ];
for (@$f)
{
$r->{id}->{$_->id} = $_;

View File

@ -919,7 +919,8 @@ sub run_create_validators {
return $params;
}
sub update {
sub update
{
my $self = shift;
my $dbh = Bugzilla->dbh;
my $user = Bugzilla->user;
@ -932,24 +933,24 @@ sub update {
$changes->{'flagtypes.name'} = [$removed, $added];
}
# Record changes in the activity table.
my $sth = $dbh->prepare('INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when,
fieldid, removed, added)
VALUES (?, ?, ?, ?, ?, ?, ?)');
foreach my $field (keys %$changes) {
my $change = $changes->{$field};
$field = "attachments.$field" unless $field eq "flagtypes.name";
my $fieldid = get_field_id($field);
$sth->execute($self->bug_id, $self->id, $user->id, $timestamp,
$fieldid, $change->[0], $change->[1]);
# Log activity
my $c;
foreach my $field (keys %$changes)
{
$c = $changes->{$field};
$field = "attachments.$field" unless $field eq 'flagtypes.name';
Bugzilla::Bug::LogActivityEntry(
$self->bug_id, $field, $c->[0], $c->[1],
$user->id, $timestamp, $self->id
);
}
if (scalar(keys %$changes)) {
$dbh->do('UPDATE attachments SET modification_time = ? WHERE attach_id = ?',
undef, ($timestamp, $self->id));
$dbh->do('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?',
undef, ($timestamp, $self->bug_id));
if (scalar keys %$changes)
{
$dbh->do('UPDATE attachments SET modification_time = ? WHERE attach_id = ?',
undef, $timestamp, $self->id);
$dbh->do('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?',
undef, $timestamp, $self->bug_id);
}
return $changes;

View File

@ -3490,14 +3490,22 @@ sub SilentLog
}
# Update the bugs_activity table to reflect changes made in bugs.
sub LogActivityEntry {
my ($i, $col, $removed, $added, $whoid, $timestamp) = @_;
sub LogActivityEntry
{
my ($bug_id, $col, $removed, $added, $whoid, $timestamp, $attach_id) = @_;
my $f = Bugzilla->get_field($col);
if (!$f->{has_activity})
{
$f->{has_activity} = 1;
$f->update;
}
my $dbh = Bugzilla->dbh;
# in the case of CCs, deps, and keywords, there's a possibility that someone
# might try to add or remove a lot of them at once, which might take more
# space than the activity table allows. We'll solve this by splitting it
# into multiple entries if it's too long.
while ($removed || $added) {
while ($removed || $added)
{
my ($removestr, $addstr) = ($removed, $added);
if (length($removestr) > MAX_LINE_LENGTH) {
my $commaposition = find_wrap_point($removed, MAX_LINE_LENGTH);
@ -3517,11 +3525,11 @@ sub LogActivityEntry {
}
trick_taint($addstr);
trick_taint($removestr);
my $fieldid = get_field_id($col);
$dbh->do("INSERT INTO bugs_activity
(bug_id, who, bug_when, fieldid, removed, added)
VALUES (?, ?, ?, ?, ?, ?)",
undef, ($i, $whoid, $timestamp, $fieldid, $removestr, $addstr));
$dbh->do(
"INSERT INTO bugs_activity (bug_id, who, bug_when, fieldid, removed, added, attach_id)".
" VALUES (?, ?, ".($timestamp ? "?" : "NOW()").", ?, ?, ?)", undef,
$bug_id, $whoid, ($timestamp ? ($timestamp) : ()), $f->id, $removestr, $addstr, $attach_id
);
}
}

View File

@ -105,6 +105,7 @@ use constant DB_COLUMNS => qw(
visibility_field_id
value_field_id
delta_ts
has_activity
);
use constant REQUIRED_CREATE_FIELDS => qw(name description);
@ -138,6 +139,7 @@ use constant UPDATE_COLUMNS => qw(
value_field_id
type
delta_ts
has_activity
);
# How various field types translate into SQL data definitions.
@ -486,6 +488,8 @@ sub is_select {
|| $_[0]->type == FIELD_TYPE_MULTI_SELECT) ? 1 : 0
}
sub has_activity { $_[0]->{has_activity} }
sub legal_values
{
my $self = shift;
@ -837,10 +841,7 @@ sub touch
{
my $self = shift;
$self->{delta_ts} = POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime);
Bugzilla->dbh->do(
"UPDATE fielddefs SET delta_ts=? WHERE id=?",
undef, $self->{delta_ts}, $self->id
);
$self->update;
}
=pod

View File

@ -173,11 +173,14 @@ sub update {
my ($changes, $old_self) = $self->SUPER::update(@_);
if (exists $changes->{$self->NAME_FIELD}) {
my ($old, $new) = @{ $changes->{$self->NAME_FIELD} };
if ($self->field->type == FIELD_TYPE_MULTI_SELECT) {
if ($self->field->type == FIELD_TYPE_MULTI_SELECT)
{
$dbh->do("UPDATE bug_$fname SET value = ? WHERE value = ?",
undef, $new, $old);
}
else {
else
{
$self->field->{has_activity} = 1;
$dbh->do(
"INSERT INTO bugs_activity (bug_id, who, bug_when, fieldid, added, removed)".
" SELECT bug_id, ?, NOW(), ?, ?, ? FROM bugs WHERE $fname = ?", undef,

View File

@ -133,6 +133,7 @@ sub update
if (exists $changes->{value})
{
# Record activity
$self->field->{has_activity} = 1;
$dbh->do(
'INSERT INTO bugs_activity (bug_id, who, bug_when, fieldid, added, removed)'.
' SELECT bug_id, ?, NOW(), ?, ?, ? FROM bugs WHERE target_milestone = ? AND product_id = ?', undef,

View File

@ -98,89 +98,85 @@ sub COLUMN_ALIASES
my $cache = Bugzilla->cache_fields;
return $cache->{column_aliases} if $cache->{column_aliases};
my $COLUMN_ALIASES = {
opendate => 'creation_ts',
opendate => 'creation_ts',
changeddate => 'delta_ts',
actual_time => 'work_time',
'[Bug creation]' => 'creation_ts',
};
Bugzilla::Hook::process('search_column_aliases', { aliases => $COLUMN_ALIASES });
return $cache->{column_aliases} = $COLUMN_ALIASES;
}
# This constant defines the columns that can be selected in a query
# and/or displayed in a bug list. Column records include the following
# fields:
#
# 1. id: a unique identifier by which the column is referred in code;
#
# 2. name: The name of the column in the database (may also be an expression
# that returns the value of the column);
# STATIC_COLUMNS and COLUMNS define the columns that can be selected in a query
# and/or displayed in a bug list. These are hashes of hashes. The key is field
# name, and the value is a hash with following data:
#
# 1. name: SQL code for field value.
# 2. joins: arrayref of table join SQL code needed to use this value.
# 3. title: The title of the column as displayed to users.
# 4. nobuglist: 1 for fields that cannot be displayed in bug list.
# 5. nocharts: 1 for fields that cannot be used in Boolean Charts.
#
# Note: There are a few hacks in the code that deviate from these definitions.
# In particular, when the list is sorted by the "votes" field the word
# "DESC" is added to the end of the field to sort in descending order,
# and the redundant short_desc column is removed when the client
# requests "all" columns.
#
# This is really a constant--that is, once it's been called once, the value
# will always be the same unless somebody adds a new custom field. But
# we have to do a lot of work inside the subroutine to get the data,
# and we don't want it to happen at compile time, so we have it as a
# subroutine.
sub COLUMNS
# STATIC_COLUMNS is a constant and is freely cached between requests.
# COLUMNS is a subroutine that takes STATIC_COLUMNS, copies the hash,
# modifies it for the needs of current request and caches once per request.
# I.e. it removes time-tracking fields for non-timetrackers etc.
sub STATIC_COLUMNS
{
my $dbh = Bugzilla->dbh;
my $cache = Bugzilla->cache_fields;
return $cache->{columns} if $cache->{columns};
# These are columns that don't exist in fielddefs, but are valid buglist
# columns. (Also see near the bottom of this function for the definition
# of short_short_desc.)
my %columns = (
relevance => { title => 'Relevance' },
assigned_to_realname => { title => 'Assignee' },
reporter_realname => { title => 'Reporter' },
qa_contact_realname => { title => 'QA Contact' },
);
# ---- vfilippov@custis.ru 2010-02-02
# The previous sql code:
# "(SUM(ldtime.work_time) * COUNT(DISTINCT ldtime.bug_when)/COUNT(bugs.bug_id))"
# was probably written by Australopithecus.
my $actual_time = '(SELECT SUM(ldtime.work_time) FROM longdescs ldtime WHERE ldtime.bug_id=bugs.bug_id)';
my %special_sql = (
deadline => $dbh->sql_date_format('bugs.deadline', '%Y-%m-%d'),
work_time => $actual_time,
percentage_complete =>
"(CASE WHEN $actual_time + bugs.remaining_time = 0.0 THEN 0.0" .
" ELSE 100 * ($actual_time / ($actual_time + bugs.remaining_time)) END)",
'flagtypes.name' => $dbh->sql_group_concat('DISTINCT ' . $dbh->sql_string_concat('flagtypes.name', 'flags.status'), "', '"),
my %columns = (
relevance => { title => 'Relevance' },
assigned_to_realname => { title => 'Assignee', nocharts => 1 },
reporter_realname => { title => 'Reporter', nocharts => 1 },
qa_contact_realname => { title => 'QA Contact', nocharts => 1 },
deadline => { name => $dbh->sql_date_format('bugs.deadline', '%Y-%m-%d') },
work_time => { name => $actual_time },
percentage_complete => {
name => "(CASE WHEN $actual_time + bugs.remaining_time = 0.0 THEN 0.0" .
" ELSE 100 * ($actual_time / ($actual_time + bugs.remaining_time)) END)",
},
'flagtypes.name' => {
name => $dbh->sql_group_concat('DISTINCT ' . $dbh->sql_string_concat('flagtypes.name', 'flags.status'), "', '"),
joins => [
"LEFT JOIN flags ON flags.bug_id = bugs.bug_id AND attach_id IS NULL",
"LEFT JOIN flagtypes ON flagtypes.id = flags.type_id"
],
},
);
# Fields that are email addresses
my @email_fields = qw(assigned_to reporter qa_contact);
# Other fields that are stored in the bugs table as an id, but
# should be displayed using their name.
my @id_fields = qw(product component classification);
foreach my $col (@email_fields)
{
my $sql = "map_${col}.login_name";
if (!Bugzilla->user->id) {
if (!Bugzilla->user->id)
{
$sql = $dbh->sql_string_until($sql, $dbh->quote('@'));
}
$special_sql{$col} = $sql;
$columns{"${col}_realname"}->{name} = "map_${col}.realname";
$columns{$col.'_realname'}{name} = "map_${col}.realname";
$columns{$col}{name} = $sql;
$columns{$col}{joins} = $columns{"${col}_realname"}{joins} =
[ "LEFT JOIN profiles AS map_$col ON bugs.$col = map_$col.userid" ];
}
# Other fields that are stored in the bugs table as an id, but
# should be displayed using their name.
my @id_fields = qw(product component classification);
foreach my $col (@id_fields)
{
$special_sql{$col} = "map_${col}s.name";
$columns{$col}{name} = "map_${col}s.name";
$columns{$col}{joins} = [
"INNER JOIN ${col}s AS map_${col}s ON ".
($col eq 'classification' ? "map_products" : "bugs").
@ -193,50 +189,82 @@ sub COLUMNS
}
# Do the actual column-getting from fielddefs, now.
foreach my $field (Bugzilla->get_fields({ buglist => 1 }))
my @bugsjoin;
foreach my $field (Bugzilla->get_fields)
{
my $id = $field->name;
my $sql = 'bugs.' . $field->name;
$sql = $special_sql{$id} if exists $special_sql{$id};
$columns{$id}{name} = $sql;
$columns{$id}{name} ||= 'bugs.' . $field->name;
$columns{$id}{title} = $field->description;
# "Joins"
$columns{$id}{nobuglist} = !$field->buglist;
if ($field->type == FIELD_TYPE_BUG_ID)
{
my $join = [ "LEFT JOIN bugs bugs_$id ON bugs_$id.bug_id=bugs.$id" ];
foreach my $subfield (Bugzilla->get_fields({ obsolete => 0, buglist => 1 }))
push @bugsjoin, $field;
}
}
# Fields of bugs related to selected
foreach my $field (@bugsjoin)
{
my $id = $field->name;
my $join = [ "LEFT JOIN bugs bugs_$id ON bugs_$id.bug_id=bugs.$id" ];
foreach my $subfield (Bugzilla->get_fields({ obsolete => 0, buglist => 1 }))
{
my $subid = $subfield->name;
if ($columns{$subid}{name} ne "bugs.$subid")
{
my $subid = $subfield->name;
if (!$special_sql{$subid})
{
$columns{$id.'_'.$subid} = {
name => "bugs_$id.".$subfield->name,
title => $field->description . ' ' . $subfield->description,
joins => $join,
subid => $subid,
};
}
$columns{$id.'_'.$subid} = {
name => "bugs_$id.".$subfield->name,
title => $field->description . ' ' . $subfield->description,
joins => $join,
subid => $subid,
};
}
}
}
$columns{'flagtypes.name'}{joins} = [
"LEFT JOIN flags ON flags.bug_id = bugs.bug_id AND attach_id IS NULL",
"LEFT JOIN flagtypes ON flagtypes.id = flags.type_id"
];
# short_short_desc is short_desc truncated to 60 characters
# see template list/table.html.tmpl
$columns{short_short_desc} = $columns{short_desc};
# The short_short_desc column is identical to short_desc
$columns{'short_short_desc'} = $columns{'short_desc'};
Bugzilla::Hook::process('buglist_columns', { columns => \%columns });
Bugzilla::Hook::process('buglist_static_columns', { columns => \%columns });
$cache->{columns} = \%columns;
return $cache->{columns};
}
# Create a new Search
# Copy and modify STATIC_COLUMNS for current user / request
sub COLUMNS
{
my $cache = Bugzilla->rc_cache_fields;
return $cache->{columns} if $cache->{columns};
my %columns = %{ STATIC_COLUMNS() };
if (!Bugzilla->user->is_timetracker)
{
delete $columns{$_} for TIMETRACKING_FIELDS;
}
Bugzilla::Hook::process('buglist_columns', { columns => \%columns });
return $cache->{columns} = \%columns;
}
# This is now used only by query.cgi
sub CHANGEDFROMTO_FIELDS
{
# creation_ts, longdesc, longdescs.isprivate, commenter
# are treated specially and always have has_activity
# (see install_update_fielddefs CustIS hook)
my @fields = grep { $_->{name} } Bugzilla->get_fields({ has_activity => 1 });
if (!Bugzilla->user->is_timetracker)
{
my %tt_fields = map { $_ => 1 } TIMETRACKING_FIELDS;
@fields = grep { !$tt_fields{$_->name} } @fields;
}
return \@fields;
}
# Create a new Bugzilla::Search object
# Note that the param argument may be modified by Bugzilla::Search
sub new {
sub new
{
my $invocant = shift;
my $class = ref($invocant) || $invocant;
@ -248,50 +276,6 @@ sub new {
return $self;
}
# Fields for Boolean Charts
sub CHART_FIELDS
{
my $cache = Bugzilla->cache_fields;
if (!$cache->{chart_fields})
{
my $hash = { map { $_->{name} => $_ } Bugzilla->get_fields };
my %cols = %{ COLUMNS() };
for (keys %cols)
{
if (!$hash->{$_} && (!/^(.*)_realname$/ || !$hash->{$1}) && $cols{$_}{name})
{
$hash->{$_} = {
name => $_,
description => $cols{$_}{title},
};
}
}
if (!Bugzilla->user->is_timetracker)
{
delete $hash->{$_} for TIMETRACKING_FIELDS;
}
$cache->{chart_fields} = $hash;
}
return $cache->{chart_fields};
}
sub CHANGEDFROMTO_FIELDS
{
my $cache = Bugzilla->cache_fields;
if (!$cache->{changedfromto_fields})
{
my $ids = Bugzilla->dbh->selectcol_arrayref('SELECT DISTINCT fieldid FROM bugs_activity');
my $tt_fields = Bugzilla->user->is_timetracker ? {} : { map { $_ => 1 } TIMETRACKING_FIELDS };
my $fields = [
sort { $a->description cmp $b->description }
grep { !$tt_fields->{$_->name} }
map { Bugzilla->get_field($_) } @$ids
];
$cache->{changedfromto_fields} = $fields;
}
return $cache->{changedfromto_fields};
}
sub init
{
my $self = shift;
@ -365,7 +349,7 @@ sub init
my @bug_statuses = $params->param('bug_status');
# Also include inactive bug statuses, as you can query them.
my @legal_statuses =
map {$_->name} @{Bugzilla->get_field('bug_status')->legal_values};
map {$_->name} @{Bugzilla->get_field('bug_status')->legal_values};
# Filter out any statuses that have been removed completely that are still
# being used by the client
@ -490,6 +474,7 @@ sub init
$chfieldfrom = '' if ($chfieldfrom eq 'now');
$chfieldto = '' if ($chfieldto eq 'now');
my @chfield = $params->param('chfield');
$_ = COLUMN_ALIASES->{$_} || $_ for @chfield;
my $chvalue = trim($params->param('chfieldvalue')) || '';
# 2003-05-20: The 'changedin' field is no longer in the UI, but we continue
@ -504,7 +489,7 @@ sub init
if (!$chfieldfrom
&& !$chfieldto
&& scalar(@chfield) == 1
&& $chfield[0] eq "[Bug creation]")
&& $chfield[0] eq 'creation_ts')
{
# Deal with the special case where the query is using changedin
# to get bugs created in the last n days by converting the value
@ -540,16 +525,13 @@ sub init
# CustIS Bug 68921 - a dirty hack: "interval worktime" column
$Bugzilla::Search::interval_from = SqlifyDate($chfieldfrom);
$Bugzilla::Search::interval_to = SqlifyDate($chfieldto);
COLUMNS->{interval_time} = {
name =>
"(SELECT IFNULL(SUM(ldtime.work_time),0) FROM longdescs ldtime".
" WHERE ldtime.bug_id=bugs.bug_id".
($sql_chfrom?" AND ldtime.bug_when>=$sql_chfrom":"").
($sql_chto ?" AND ldtime.bug_when<=$sql_chto":"").
($chfieldwho?" AND ldtime.who=$chfieldwho":"").
")",
title => "Interval worktime",
};
COLUMNS->{interval_time}->{name} =
"(SELECT COALESCE(SUM(ldtime.work_time),0) FROM longdescs ldtime".
" WHERE ldtime.bug_id=bugs.bug_id".
($sql_chfrom?" AND ldtime.bug_when>=$sql_chfrom":"").
($sql_chto ?" AND ldtime.bug_when<=$sql_chto":"").
($chfieldwho?" AND ldtime.who=$chfieldwho":"").
")";
my $sql_chvalue = $chvalue ne '' ? $dbh->quote($chvalue) : '';
trick_taint($sql_chvalue);
@ -566,9 +548,10 @@ sub init
foreach my $f (@chfield)
{
my $term;
if ($f eq "[Bug creation]")
if ($f eq 'creation_ts')
{
# Treat [Bug creation] differently because we need to look
# Treat creation_ts (and [Bug creation] through aliases)
# differently because we need to look
# at bugs.creation_ts rather than the bugs_activity table.
my @l;
if ($sql_chfrom) {
@ -1036,7 +1019,8 @@ sub init
$f = COLUMN_ALIASES->{$f} if COLUMN_ALIASES->{$f};
# chart -1 is generated by other code above, not from the user-
# submitted form, so we'll blindly accept any values in chart -1
if (!CHART_FIELDS->{$f} && $chart != -1) {
if (!COLUMNS->{$f} && $chart != -1)
{
ThrowCodeError("invalid_field_name", {field => $f});
}
if (COLUMNS->{$f})
@ -2533,10 +2517,11 @@ sub _changedbefore_changedafter {
my $operator = ($$t =~ /before/) ? '<' : '>';
my $table = "act_$$chartid";
my $fieldid = CHART_FIELDS->{$$f}->{id};
my $fieldid = Bugzilla->get_field($$f);
if (!$fieldid) {
ThrowCodeError("invalid_field_name", {field => $$f});
}
$fieldid = $fieldid->id;
push(@$supptables, "LEFT JOIN bugs_activity AS $table " .
"ON $table.bug_id = bugs.bug_id " .
"AND $table.fieldid = $fieldid " .
@ -2553,10 +2538,11 @@ sub _changedfrom_changedto {
my $operator = ($$t =~ /from/) ? 'removed' : 'added';
my $table = "act_$$chartid";
my $fieldid = CHART_FIELDS->{$$f}->{id};
my $fieldid = Bugzilla->get_field($$f);
if (!$fieldid) {
ThrowCodeError("invalid_field_name", {field => $$f});
}
$fieldid = $fieldid->id;
push(@$supptables, "LEFT JOIN bugs_activity AS $table " .
"ON $table.bug_id = bugs.bug_id " .
"AND $table.fieldid = $fieldid " .
@ -2572,11 +2558,11 @@ sub _changedby
@func_args{qw(chartid f v supptables term)};
my $table = "act_$$chartid";
my $fieldid = CHART_FIELDS->{$$f}->{id};
if (!$fieldid)
{
my $fieldid = Bugzilla->get_field($$f);
if (!$fieldid) {
ThrowCodeError("invalid_field_name", {field => $$f});
}
$fieldid = $fieldid->id;
my $id = login_to_id($$v, THROW_ERROR);
push @$supptables, "LEFT JOIN bugs_activity AS $table " .
"ON $table.bug_id = bugs.bug_id " .

View File

@ -154,6 +154,7 @@ sub update
if (exists $changes->{value})
{
# Record activity
$self->field->{has_activity} = 1;
$dbh->do(
'INSERT INTO bugs_activity (bug_id, who, bug_when, fieldid, added, removed)'.
' SELECT bug_id, ?, NOW(), ?, ?, ? FROM bugs WHERE version = ? AND product_id = ?', undef,

View File

@ -42,52 +42,10 @@ my $cgi = Bugzilla->cgi;
my $template = Bugzilla->template;
my $vars = {};
# The master list not only says what fields are possible, but what order
# they get displayed in.
my @masterlist = ("creation_ts", "delta_ts", "bug_severity", "priority");
push @masterlist, "rep_platform" if Bugzilla->params->{useplatform};
push @masterlist, "assigned_to", "assigned_to_realname",
"reporter", "reporter_realname", "bug_status",
"resolution";
if (Bugzilla->params->{"useclassification"}) {
push(@masterlist, "classification");
}
push @masterlist, "product", "component", "version";
push @masterlist, "op_sys" if Bugzilla->params->{useopsys};
if (Bugzilla->params->{"usevotes"}) {
push (@masterlist, "votes");
}
if (Bugzilla->params->{"usebugaliases"}) {
unshift(@masterlist, "alias");
}
if (Bugzilla->params->{"usetargetmilestone"}) {
push(@masterlist, "target_milestone");
}
if (Bugzilla->params->{"useqacontact"}) {
push(@masterlist, "qa_contact");
push(@masterlist, "qa_contact_realname");
}
if (Bugzilla->params->{"usestatuswhiteboard"}) {
push(@masterlist, "status_whiteboard");
}
if (Bugzilla::Keyword->any_exist) {
push(@masterlist, "keywords");
}
if (Bugzilla->has_flags) {
push(@masterlist, "flagtypes.name");
}
if (Bugzilla->user->is_timetracker) {
push(@masterlist, "estimated_time", "remaining_time", "work_time", "percentage_complete", "deadline");
}
push(@masterlist, ("short_desc", "short_short_desc"));
my @custom_fields = grep { $_->type != FIELD_TYPE_MULTI_SELECT }
Bugzilla->active_custom_fields;
push(@masterlist, map { $_->name } @custom_fields);
my @masterlist =
sort map { $_->{title} }
grep { !$_->{nobuglist} }
values %{ Bugzilla::Search->COLUMNS };
Bugzilla::Hook::process('colchange_columns', {'columns' => \@masterlist} );

View File

@ -34,8 +34,8 @@ set_hook('custis', 'install_update_db', 'CustisDBHooks::install_upda
set_hook('custis', 'install_update_fielddefs', 'CustisDBHooks::install_update_fielddefs');
# Хуки в показ списка багов
set_hook('custis', 'buglist_static_columns', 'CustisBuglistHooks::buglist_static_columns');
set_hook('custis', 'buglist_columns', 'CustisBuglistHooks::buglist_columns');
set_hook('custis', 'colchange_columns', 'CustisBuglistHooks::colchange_columns');
# Хуки в обработку почты
set_hook('custis', 'bugmail_pre_template', 'CustisMailHooks::bugmail_pre_template');

View File

@ -7,7 +7,7 @@ use strict;
use Bugzilla::Search;
use Bugzilla::Util;
sub buglist_columns
sub buglist_static_columns
{
my ($args) = @_;
my $columns = $args->{columns};
@ -53,9 +53,6 @@ WHERE col_f.bug_id=bugs.bug_id AND col_ft.is_requesteeble=1 AND col_ft.is_reques
# CustIS Bug 71955 - first comment to the bug
$columns->{comment0} = {
name =>
"(SELECT thetext FROM longdescs ldc0 WHERE ldc0.bug_id = bugs.bug_id ".
(Bugzilla->user->is_insider ? "" : "AND ldc0.isprivate=0 ")." ORDER BY ldc0.bug_when LIMIT 1)",
title => "First Comment",
};
@ -71,17 +68,15 @@ WHERE col_f.bug_id=bugs.bug_id AND col_ft.is_requesteeble=1 AND col_ft.is_reques
return 1;
}
sub colchange_columns
sub buglist_columns
{
my ($args) = @_;
my $columns = $args->{columns};
my $defs = Bugzilla::Search->COLUMNS;
for (sort keys %$defs)
{
push @$columns, $_ if lsearch($columns, $_) < 0 && $_ ne 'bug_id';
}
@$columns = sort { $defs->{$a}->{title} cmp $defs->{$b}->{title} } @$columns;
# CustIS Bug 71955 - first comment to the bug
$columns->{comment0}->{name} =
"(SELECT thetext FROM longdescs ldc0 WHERE ldc0.bug_id = bugs.bug_id ".
(Bugzilla->user->is_insider ? "" : "AND ldc0.isprivate=0 ")." ORDER BY ldc0.bug_when LIMIT 1)";
return 1;
}

View File

@ -113,6 +113,7 @@ sub db_schema_abstract_schema
# Bug 70605 - Кэширование зависимостей полей для поиска и формы бага на клиентской стороне
push @{$schema->{fielddefs}->{FIELDS}}, delta_ts => {TYPE => 'DATETIME'};
push @{$schema->{fielddefs}->{FIELDS}}, has_activity => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 0};
# Bug 68921 - Предикаты корректности из запросов поиска
$schema->{checkers} = {
@ -360,6 +361,16 @@ sub install_update_fielddefs
$dbh->do('UPDATE fielddefs SET delta_ts=NOW()');
}
if (!$dbh->bz_column_info('fielddefs', 'has_activity'))
{
$dbh->bz_add_column('fielddefs', has_activity => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 0});
$dbh->do(
'UPDATE fielddefs SET has_activity=1'.
' WHERE id IN (SELECT DISTINCT fieldid FROM bugs_activity)'.
' OR name IN (\'longdesc\', \'longdescs.isprivate\', \'commenter\', \'creation_ts\')'
);
}
return 1;
}

View File

@ -199,12 +199,13 @@ if (!scalar(@{$default{'chfieldto'}}) || $default{'chfieldto'}->[0] eq "") {
# Fields for boolean charts
$vars->{fields} = [
sort { $a->{description} cmp $b->{description} }
values %{ Bugzilla::Search::CHART_FIELDS() }
sort { $a->{title} cmp $b->{title} }
grep { !$_->{nocharts} }
values %{ Bugzilla::Search->COLUMNS }
];
# "where one or more of the following changed:"
$vars->{chfield} = [ map { $_->name } @{ &Bugzilla::Search::CHANGEDFROMTO_FIELDS } ];
$vars->{chfield} = [ map { $_->name } @{ Bugzilla::Search->CHANGEDFROMTO_FIELDS } ];
# Another hack...
unshift @{$vars->{fields}}, { name => "noop", description => "---" };

View File

@ -128,7 +128,6 @@
# across all templates--see VARIABLES in Bugzilla/Template.pm.
#%]
[% vars.field_descs = {
"[Bug creation]" => "[$terms.Bug creation]",
"actual_time" => "Actual Hours",
"alias" => "Alias",
"assigned_to" => "Assignee",
@ -154,6 +153,7 @@
"component_id" => "Component ID",
"component" => "Component",
"content" => "Content",
"[Bug creation]" => "Creation date",
"opendate" => "Creation date",
"creation_ts" => "Creation date",
"deadline" => "Deadline",

View File

@ -67,13 +67,13 @@
size="15" multiple="multiple" onchange="updateView();">
[% FOREACH column = collist %]
<option value="[% column FILTER html %]" selected="selected">
[% Bugzilla.cache_fields.columns.${column}.title || column | html %]
[% Bugzilla.COLUMNS.${column}.title || column | html %]
</option>
[% END %]
[% FOREACH column = masterlist %]
[% IF lsearch(collist, column) == -1 %]
<option value="[% column FILTER html %]">
[% Bugzilla.cache_fields.columns.${column}.title || column | html %]
[% Bugzilla.COLUMNS.${column}.title || column | html %]
</option>
[% END %]
[% END %]

View File

@ -1,11 +1,11 @@
[% IF search_description && search_description.size %]
<ul class="search_description">
[% c = Bugzilla.cache_fields.chart_fields %]
[% a = Bugzilla.cache_fields.field_aliases %]
[% c = Bugzilla.COLUMNS %]
[% a = Bugzilla.COLUMN_ALIASES %]
[% FOREACH i = search_description %]
<li>
[% IF i.field %]
<span class="search_field">[% c.${i.field}.description || c.${a.${i.field}}.description || i.field | html %]:</span>
<span class="search_field">[% c.${i.field}.title || c.${a.${i.field}}.title || i.field | html %]:</span>
[% END %]
[% IF search_shown_types.${i.type} || debug %]
([% search_descs.${i.type} | html %])

View File

@ -191,7 +191,7 @@
[% FOREACH column = displaycolumns %]
<td class="bz_[% column FILTER css_class_quote %]_column
[%- IF Bugzilla.search_cache.columns.$column.subid %] bz_[% Bugzilla.cache_fields.columns.$column.subid | css_class_quote %]_column[% END %]">
[%- IF Bugzilla.COLUMNS.$column.subid %] bz_[% Bugzilla.COLUMNS.$column.subid | css_class_quote %]_column[% END %]">
[% IF abbrev.$column.maxlength %]
<span title="[%- display_value(column, bug.$column) FILTER html %]">
[% END %]

View File

@ -552,7 +552,6 @@ YAHOO.util.Event.addListener(window, 'load', function() {
[% END %]
<select name="chfield" id="chfield" multiple="multiple" size="4">
<option value="[Bug creation]">[Bug creation]</option>
[% FOREACH field = chfields.sort('desc') %]
<option value="[% field.value FILTER html %]"
[% " selected" IF lsearch(default.chfield, field.value) != -1 %]>