Bug 70605 - Fix field caching
git-svn-id: svn://svn.office.custis.ru/3rdparty/bugzilla.org/trunk@1162 6955db30-a419-402b-8a0d-67ecbb4d7f56master
parent
4820bfd388
commit
21f46cb467
14
Bugzilla.pm
14
Bugzilla.pm
|
@ -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} = $_;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 " .
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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} );
|
||||
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 => "---" };
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 %]
|
||||
|
|
|
@ -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 %])
|
||||
|
|
|
@ -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 %]
|
||||
|
|
|
@ -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 %]>
|
||||
|
|
Loading…
Reference in New Issue