[Rt-commit] r17928 - in rt/3.999/branches/merge_to_3.8.2: .
sunnavy at bestpractical.com
sunnavy at bestpractical.com
Mon Jan 26 06:51:05 EST 2009
Author: sunnavy
Date: Mon Jan 26 06:51:01 2009
New Revision: 17928
Modified:
rt/3.999/branches/merge_to_3.8.2/ (props changed)
rt/3.999/branches/merge_to_3.8.2/lib/RT/Model/TicketCollection.pm
Log:
r19057 at sunnavys-mb: sunnavy | 2009-01-26 19:32:31 +0800
merged lib/RT/Model/TicketCollection.pm
Modified: rt/3.999/branches/merge_to_3.8.2/lib/RT/Model/TicketCollection.pm
==============================================================================
--- rt/3.999/branches/merge_to_3.8.2/lib/RT/Model/TicketCollection.pm (original)
+++ rt/3.999/branches/merge_to_3.8.2/lib/RT/Model/TicketCollection.pm Mon Jan 26 06:51:01 2009
@@ -95,59 +95,59 @@
# metadata.
our %FIELD_METADATA = (
- Status => [ 'ENUM', ],
- Queue => [ 'ENUM' => 'Queue', ],
- Type => [ 'ENUM', ],
- Creator => [ 'ENUM' => 'User', ],
- LastUpdatedBy => [ 'ENUM' => 'User', ],
- Owner => [ 'WATCHERFIELD' => 'Owner', ],
- EffectiveId => [ 'INT', ],
- Id => [ 'INT', ],
- InitialPriority => [ 'INT', ],
- FinalPriority => [ 'INT', ],
- Priority => [ 'INT', ],
- TimeLeft => [ 'INT', ],
- TimeWorked => [ 'INT', ],
- TimeEstimated => [ 'INT', ],
-
- Linked => ['LINK'],
- LinkedTo => [ 'LINK' => 'To' ],
- LinkedFrom => [ 'LINK' => 'From' ],
- MemberOf => [ 'LINK' => To => 'MemberOf', ],
- DependsOn => [ 'LINK' => To => 'DependsOn', ],
- RefersTo => [ 'LINK' => To => 'RefersTo', ],
- HasMember => [ 'LINK' => From => 'MemberOf', ],
- DependentOn => [ 'LINK' => From => 'DependsOn', ],
- DependedOnBy => [ 'LINK' => From => 'DependsOn', ],
- ReferredToBy => [ 'LINK' => From => 'RefersTo', ],
- Told => [ 'DATE' => 'Told', ],
- Starts => [ 'DATE' => 'starts', ],
- Started => [ 'DATE' => 'Started', ],
- Due => [ 'DATE' => 'Due', ],
- Resolved => [ 'DATE' => 'resolved', ],
- LastUpdated => [ 'DATE' => 'last_updated', ],
- Created => [ 'DATE' => 'Created', ],
- Subject => [ 'STRING', ],
- Content => [ 'TRANSFIELD', ],
- ContentType => [ 'TRANSFIELD', ],
- Filename => [ 'TRANSFIELD', ],
- TransactionDate => [ 'TRANSDATE', ],
- Requestor => [ 'WATCHERFIELD' => 'requestor', ],
- Requestors => [ 'WATCHERFIELD' => 'requestor', ],
- Cc => [ 'WATCHERFIELD' => 'cc', ],
- AdminCc => [ 'WATCHERFIELD' => 'admin_cc', ],
- Watcher => [ 'WATCHERFIELD', ],
- QueueCc => [ 'WATCHERFIELD' => 'Cc' => 'Queue', ],
- QueueAdminCc => [ 'WATCHERFIELD' => 'AdminCc' => 'Queue', ],
- QueueWatcher => [ 'WATCHERFIELD' => undef => 'Queue', ],
- CustomFieldValue => [ 'CUSTOMFIELD', ],
- CustomField => [ 'CUSTOMFIELD', ],
- CF => [ 'CUSTOMFIELD', ],
- Updated => [ 'TRANSDATE', ],
- RequestorGroup => [ 'MEMBERSHIPFIELD' => 'requestor', ],
- CcGroup => [ 'MEMBERSHIPFIELD' => 'cc', ],
- AdminCcGroup => [ 'MEMBERSHIPFIELD' => 'admin_cc', ],
- WatcherGroup => [ 'MEMBERSHIPFIELD', ],
+ Status => [ 'ENUM', ], #loc_left_pair
+ Queue => [ 'ENUM' => 'Queue', ], #loc_left_pair
+ Type => [ 'ENUM', ], #loc_left_pair
+ Creator => [ 'ENUM' => 'User', ], #loc_left_pair
+ LastUpdatedBy => [ 'ENUM' => 'User', ], #loc_left_pair
+ Owner => [ 'WATCHERFIELD' => 'Owner', ], #loc_left_pair
+ EffectiveId => [ 'INT', ], #loc_left_pair
+ Id => [ 'INT', ], #loc_left_pair
+ InitialPriority => [ 'INT', ], #loc_left_pair
+ FinalPriority => [ 'INT', ], #loc_left_pair
+ Priority => [ 'INT', ], #loc_left_pair
+ TimeLeft => [ 'INT', ], #loc_left_pair
+ TimeWorked => [ 'INT', ], #loc_left_pair
+ TimeEstimated => [ 'INT', ], #loc_left_pair
+
+ Linked => ['LINK'], #loc_left_pair
+ LinkedTo => [ 'LINK' => 'To' ], #loc_left_pair
+ LinkedFrom => [ 'LINK' => 'From' ], #loc_left_pair
+ MemberOf => [ 'LINK' => To => 'MemberOf', ], #loc_left_pair
+ DependsOn => [ 'LINK' => To => 'DependsOn', ], #loc_left_pair
+ RefersTo => [ 'LINK' => To => 'RefersTo', ], #loc_left_pair
+ HasMember => [ 'LINK' => From => 'MemberOf', ], #loc_left_pair
+ DependentOn => [ 'LINK' => From => 'DependsOn', ], #loc_left_pair
+ DependedOnBy => [ 'LINK' => From => 'DependsOn', ], #loc_left_pair
+ ReferredToBy => [ 'LINK' => From => 'RefersTo', ], #loc_left_pair
+ Told => [ 'DATE' => 'Told', ], #loc_left_pair
+ Starts => [ 'DATE' => 'starts', ], #loc_left_pair
+ Started => [ 'DATE' => 'Started', ], #loc_left_pair
+ Due => [ 'DATE' => 'Due', ], #loc_left_pair
+ Resolved => [ 'DATE' => 'resolved', ], #loc_left_pair
+ LastUpdated => [ 'DATE' => 'last_updated', ], #loc_left_pair
+ Created => [ 'DATE' => 'Created', ], #loc_left_pair
+ Subject => [ 'STRING', ], #loc_left_pair
+ Content => [ 'TRANSFIELD', ], #loc_left_pair
+ ContentType => [ 'TRANSFIELD', ], #loc_left_pair
+ Filename => [ 'TRANSFIELD', ], #loc_left_pair
+ TransactionDate => [ 'TRANSDATE', ], #loc_left_pair
+ Requestor => [ 'WATCHERFIELD' => 'requestor', ], #loc_left_pair
+ Requestors => [ 'WATCHERFIELD' => 'requestor', ], #loc_left_pair
+ Cc => [ 'WATCHERFIELD' => 'cc', ], #loc_left_pair
+ AdminCc => [ 'WATCHERFIELD' => 'admin_cc', ], #loc_left_pair
+ Watcher => [ 'WATCHERFIELD', ], #loc_left_pair
+ QueueCc => [ 'WATCHERFIELD' => 'Cc' => 'Queue', ], #loc_left_pair
+ QueueAdminCc => [ 'WATCHERFIELD' => 'AdminCc' => 'Queue', ], #loc_left_pair
+ QueueWatcher => [ 'WATCHERFIELD' => undef => 'Queue', ], #loc_left_pair
+ CustomFieldValue => [ 'CUSTOMFIELD', ], #loc_left_pair
+ CustomField => [ 'CUSTOMFIELD', ], #loc_left_pair
+ CF => [ 'CUSTOMFIELD', ], #loc_left_pair
+ Updated => [ 'TRANSDATE', ], #loc_left_pair
+ RequestorGroup => [ 'MEMBERSHIPFIELD' => 'requestor', ], #loc_left_pair
+ CcGroup => [ 'MEMBERSHIPFIELD' => 'cc', ], #loc_left_pair
+ AdminCcGroup => [ 'MEMBERSHIPFIELD' => 'admin_cc', ], #loc_left_pair
+ WatcherGroup => [ 'MEMBERSHIPFIELD', ], #loc_left_pair
);
# support _ name conventions as well
@@ -161,6 +161,7 @@
our %dispatch = (
ENUM => \&_enum_limit,
INT => \&_int_limit,
+ ID => \&_id_limit,
LINK => \&_link_limit,
DATE => \&_date_limit,
STRING => \&_string_limit,
@@ -250,6 +251,7 @@
_sql_trattachalias
_sql_u_watchers_alias_for_sort
_sql_u_watchers_aliases
+ _sql_current_user_can_see_applied
);
}
@@ -267,6 +269,61 @@
version of what ProcessRestrictions used to do. They're also much
more clearly delineated by the type of field being processed.
+=head2 _id_limit
+
+Handle ID field.
+
+=cut
+
+sub _id_limit {
+ my ( $sb, $field, $op, $value, @rest ) = @_;
+
+ return $sb->_int_limit( $field, $op, $value, @rest )
+ unless $value eq '__Bookmarked__';
+
+ die "Invalid operator $op for __Bookmarked__ search on $field"
+ unless $op =~ /^(=|!=)$/;
+
+ my @bookmarks = do {
+ my $tmp = $sb->current_user->user_object->first_attribute('Bookmarks');
+ $tmp = $tmp->content if $tmp;
+ $tmp ||= {};
+ grep $_, keys %$tmp;
+ };
+
+ return $sb->_sql_limit(
+ column => $field,
+ operator => $op,
+ value => 0,
+ @rest,
+ ) unless @bookmarks;
+
+ # as bookmarked tickets can be merged we have to use a join
+ # but it should be pretty lightweight
+ my $tickets_alias = $sb->join(
+ type => 'left',
+ alias1 => 'main',
+ column1 => 'id',
+ table2 => 'Tickets',
+ column2 => 'effective_id',
+ );
+ $sb->_open_paren;
+ my $first = 1;
+ my $ea = $op eq '=' ? 'OR' : 'AND';
+ foreach my $id ( sort @bookmarks ) {
+ $sb->_sql_limit(
+ alias => $tickets_alias,
+ column => 'id',
+ operator => $op,
+ value => $id,
+ $first ? (@rest) : ( entry_aggregator => $ea )
+ );
+ }
+ $sb->_close_paren;
+}
+
+
+
=head2 _enum_limit
Handle Fields which are limited to certain values, and potentially
@@ -926,7 +983,8 @@
leftjoin => $groups,
alias => $groups,
column => 'domain',
- value => 'RT::Model::Ticket-Role',
+ value => 'RT::' . $args{'class'} . '-Role',
+
);
$self->SUPER::limit(
leftjoin => $groups,
@@ -935,7 +993,8 @@
value => $args{'type'},
) if $args{'type'};
- $self->{'_sql_role_group_aliases'}{ $args{'type'} } = $groups
+ $self->{'_sql_role_group_aliases'}{ $args{'class'} . '-' . $args{'type'} } =
+ $groups
unless $args{'new'};
return $groups;
@@ -1303,6 +1362,14 @@
# otherwise end up with a redundant clause.
my $null_columns_ok;
+ my $fix_op = sub {
+ my $op = shift;
+ return $op unless RT->config->get('DatabaseType') eq 'Oracle';
+ return 'MATCHES' if $op eq '=';
+ return 'NOT MATCHES' if $op eq '!=';
+ return $op;
+ };
+
if ( ( $op =~ /^NOT LIKE$/i ) or ( $op eq '!=' ) ) {
$null_columns_ok = 1;
}
@@ -1332,7 +1399,7 @@
$self->_sql_limit(
alias => $TicketCFs,
column => $column,
- operator => $op,
+ operator => ( $column ne 'large_content' ? $op : $fix_op->($op) ),
value => $value,
%rest
);
@@ -1342,6 +1409,7 @@
alias => $TicketCFs,
column => 'content',
operator => $op,
+
value => $value,
%rest
);
@@ -1366,7 +1434,7 @@
$self->_sql_limit(
alias => $TicketCFs,
column => 'large_content',
- operator => $op,
+ operator => $fix_op->($op),
value => $value,
entry_aggregator => 'AND',
);
@@ -1983,37 +2051,246 @@
$self->_process_restrictions() if ( $self->{'RecalcTicketLimits'} == 1 );
- my $Ticket = $self->SUPER::next();
- if ( ( defined($Ticket) ) and ( ref($Ticket) ) ) {
+ my $Ticket = $self->SUPER::next;
+ return $Ticket unless $Ticket;
+ if ( $Ticket->__value('Status') eq 'deleted'
+ && !$self->{'allow_deleted_search'} )
+ {
+ return $self->next;
+ }
+ elsif ( RT->config->get('UseSQLForACLChecks') ) {
+
+ # if we found a ticket with this option enabled then
+ # all tickets we found are ACLed, cache this fact
+ my $key = join ";:;", $self->current_user->id, 'ShowTicket',
+ 'RT::Model::Ticket-' . $Ticket->id;
+ $RT::Principal::_ACL_CACHE->set( $key => 1 );
+ return $Ticket;
+ }
+ elsif ( $Ticket->current_user_has_right('ShowTicket') ) {
+ # has rights
+ return $Ticket;
+ }
+ else {
- if ( $Ticket->__value('status') eq 'deleted'
- && !$self->{'allow_deleted_search'} )
- {
- return ( $self->next() );
- }
+ # If the user doesn't have the right to show this ticket
+ return $self->next;
+ }
+}
- # Since Ticket could be granted with more rights instead
- # of being revoked, it's ok if queue rights allow
- # ShowTicket. It seems need another query, but we have
- # rights cache in Principal::has_right.
- elsif ( $Ticket->current_user_has_right('ShowTicket') )
- {
- return ($Ticket);
- }
+sub _do_search {
+ my $self = shift;
+ $self->current_user_can_see if RT->config->get('UseSQLForACLChecks');
+ return $self->SUPER::_do_search(@_);
+}
+
+sub _docount {
+ my $self = shift;
+ $self->current_user_can_see if RT->config->get('UseSQLForACLChecks');
+ return $self->SUPER::_docount(@_);
+}
+
+
+sub _roles_can_see {
+ my $self = shift;
+ my $cache_key = 'Roleshas_right;:;ShowTicket';
+
+ if ( my $cached = $RT::Principal::_ACL_CACHE->fetch($cache_key) ) {
+ return %$cached;
+ }
- #If the user doesn't have the right to show this ticket
+ my $ACL = RT::ACL->new(RT->system_user);
+ $ACL->limit( column => 'right_name', value => 'ShowTicket' );
+ $ACL->limit( column => 'type', operator => '!=', value => 'Group' );
+ my $principal_alias = $ACL->join(
+ alias1 => 'main',
+ column1 => 'principal_id',
+ table2 => 'Principals',
+ column2 => 'id',
+ );
+ $ACL->limit( alias => $principal_alias, column => 'disabled', value => 0 );
+
+ my %res = ();
+ while ( my $ACE = $ACL->next ) {
+ my $role = $ACE->principal_type;
+ my $type = $ACE->object_type;
+ if ( $type eq 'RT::System' ) {
+ $res{$role} = 1;
+ }
+ elsif ( $type eq 'RT::Model::Queue' ) {
+ next if $res{$role} && !ref $res{$role};
+ push @{ $res{$role} ||= [] }, $ACE->objectid;
+ }
else {
- return ( $self->next() );
+ Jifty->log->error(
+ 'ShowTicket right is granted on unsupported object');
}
}
+ $RT::Principal::_ACL_CACHE->set( $cache_key => \%res );
+ return %res;
+}
+
+sub _directly_can_see_in {
+ my $self = shift;
+ my $id = $self->current_user->id;
- #if there never was any ticket
- else {
- return (undef);
+ my $cache_key = 'User-' . $id . ';:;ShowTicket;:;DirectlyCanSeeIn';
+ if ( my $cached = $RT::Principal::_ACL_CACHE->fetch($cache_key) ) {
+ return @$cached;
}
+ my $ACL = RT::ACL->new(RT->system_user);
+ $ACL->limit( column => 'right_name', value => 'ShowTicket' );
+ my $principal_alias = $ACL->join(
+ alias1 => 'main',
+ column1 => 'principal_id',
+ table2 => 'Principals',
+ column2 => 'id',
+ );
+ $ACL->limit( alias => $principal_alias, column => 'disabled', value => 0 );
+ my $cgm_alias = $ACL->join(
+ alias1 => 'main',
+ column1 => 'principal_id',
+ table2 => 'CachedGroupMembers',
+ column2 => 'group_id',
+ );
+ $ACL->limit( alias => $cgm_alias, column => 'member_id', value => $id );
+ $ACL->limit( alias => $cgm_alias, column => 'disabled', value => 0 );
+
+ my @res = ();
+ while ( my $ACE = $ACL->next ) {
+ my $type = $ACE->object_type;
+ if ( $type eq 'RT::System' ) {
+
+ # If user is direct member of a group that has the right
+ # on the system then he can see any ticket
+ $RT::Principal::_ACL_CACHE->set( $cache_key => [-1] );
+ return (-1);
+ }
+ elsif ( $type eq 'RT::Model::Queue' ) {
+ push @res, $ACE->object_id;
+ }
+ else {
+ Jifty->log->error(
+ 'ShowTicket right is granted on unsupported object');
+ }
+ }
+ $RT::Principal::_ACL_CACHE->set( $cache_key => \@res );
+ return @res;
}
+sub current_user_can_see {
+ my $self = shift;
+ return if $self->{'_sql_current_user_can_see_applied'};
+
+ return $self->{'_sql_current_user_can_see_applied'} = 1
+ if $self->current_user->user_object->has_right(
+ right => 'SuperUser',
+ object => RT->system
+ );
+
+ my $id = $self->current_user->id;
+
+ my @direct_queues = $self->_directly_can_see_in;
+ return $self->{'_sql_current_user_can_see_applied'} = 1
+ if @direct_queues && $direct_queues[0] == -1;
+
+ my %roles = $self->_roles_can_see;
+ {
+ my %skip = map { $_ => 1 } @direct_queues;
+ foreach my $role ( keys %roles ) {
+ next unless ref $roles{$role};
+
+ my @queues = grep !$skip{$_}, @{ $roles{$role} };
+ if (@queues) {
+ $roles{$role} = \@queues;
+ }
+ else {
+ delete $roles{$role};
+ }
+ }
+ }
+
+ {
+ my $join_roles = keys %roles;
+ $join_roles = 0 if $join_roles == 1 && $roles{'Owner'};
+ my ( $role_group_alias, $cgm_alias );
+ if ($join_roles) {
+ $role_group_alias = $self->_role_groupsjoin( New => 1 );
+ $cgm_alias =
+ $self->_group_membersjoin( groups_alias => $role_group_alias );
+ $self->SUPER::limit(
+ leftjoin => $cgm_alias,
+ column => 'member_id',
+ operator => '=',
+ value => $id,
+ );
+ }
+ my $limit_queues = sub {
+ my $ea = shift;
+ my @queues = @_;
+
+ return unless @queues;
+ if ( @queues == 1 ) {
+ $self->_sql_limit(
+ alias => 'main',
+ column => 'queue',
+ value => $_[0],
+ entry_aggregator => $ea,
+ );
+ }
+ else {
+ $self->_open_paren;
+ foreach my $q (@queues) {
+ $self->_sql_limit(
+ alias => 'main',
+ column => 'queue',
+ value => $q,
+ entry_aggregator => $ea,
+ );
+ $ea = 'OR';
+ }
+ $self->_close_paren;
+ }
+ return 1;
+ };
+
+ $self->_open_paren;
+ my $ea = 'AND';
+ $ea = 'OR' if $limit_queues->( $ea, @direct_queues );
+ while ( my ( $role, $queues ) = each %roles ) {
+ $self->_open_paren;
+ if ( $role eq 'Owner' ) {
+ $self->_sql_limit(
+ column => 'Owner',
+ value => $id,
+ entry_aggregator => $ea,
+ );
+ }
+ else {
+ $self->_sql_limit(
+ alias => $cgm_alias,
+ column => 'member_id',
+ operator => 'IS NOT',
+ value => 'NULL',
+ quote_value => 0,
+ entry_aggregator => $ea,
+ );
+ $self->_sql_limit(
+ alias => $role_group_alias,
+ column => 'type',
+ value => $role,
+ entry_aggregator => 'AND',
+ );
+ }
+ $limit_queues->( 'AND', @$queues ) if ref $queues;
+ $ea = 'OR' if $ea eq 'AND';
+ $self->_close_paren;
+ }
+ $self->_close_paren;
+ }
+ return $self->{'_sql_current_user_can_see_applied'} = 1;
+}
# Convert a set of oldstyle SB Restrictions to Clauses for RQL
More information about the Rt-commit
mailing list