import rt 3.4.6
[freeside.git] / rt / lib / RT / SavedSearches.pm
1 # BEGIN BPS TAGGED BLOCK {{{
2
3 # COPYRIGHT:
4 #  
5 # This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC 
6 #                                          <jesse@bestpractical.com>
7
8 # (Except where explicitly superseded by other copyright notices)
9
10
11 # LICENSE:
12
13 # This work is made available to you under the terms of Version 2 of
14 # the GNU General Public License. A copy of that license should have
15 # been provided with this software, but in any event can be snarfed
16 # from www.gnu.org.
17
18 # This work is distributed in the hope that it will be useful, but
19 # WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 # General Public License for more details.
22
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26
27
28 # CONTRIBUTION SUBMISSION POLICY:
29
30 # (The following paragraph is not intended to limit the rights granted
31 # to you to modify and distribute this software under the terms of
32 # the GNU General Public License and is only of importance to you if
33 # you choose to contribute your changes and enhancements to the
34 # community by submitting them to Best Practical Solutions, LLC.)
35
36 # By intentionally submitting any modifications, corrections or
37 # derivatives to this work, or any other work intended for use with
38 # Request Tracker, to Best Practical Solutions, LLC, you confirm that
39 # you are the copyright holder for those contributions and you grant
40 # Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
41 # royalty-free, perpetual, license to use, copy, create derivative
42 # works based on those contributions, and sublicense and distribute
43 # those contributions and any derivatives thereof.
44
45 # END BPS TAGGED BLOCK }}}
46
47 =head1 NAME
48
49   RT::SavedSearches - a pseudo-collection for SavedSearch objects.
50
51 =head1 SYNOPSIS
52
53   use RT::SavedSearch
54
55 =head1 DESCRIPTION
56
57   SavedSearches is an object consisting of a number of SavedSearch objects.
58   It works more or less like a DBIx::SearchBuilder collection, although it
59   is not.
60
61 =head1 METHODS
62
63 =begin testing
64
65 use_ok(RT::SavedSearches);
66
67 # The real tests are in lib/t/20savedsearch.t
68
69 =end testing
70
71 =cut
72
73 package RT::SavedSearches;
74
75 use RT::Base;
76 use RT::SavedSearch;
77
78 use strict;
79 use vars qw/@ISA/;
80 @ISA = qw/RT::Base/;
81
82 sub new  {
83     my $proto = shift;
84     my $class = ref($proto) || $proto;
85     my $self  = {};
86     bless ($self, $class);
87     $self->CurrentUser(@_);
88     $self->{'idx'} = 0;
89     $self->{'objects'} = [];
90     return $self;
91 }
92
93 =head2 LimitToPrivacy
94
95 Takes two argumets: a privacy string, of the format "<class>-<id>", as
96 produced by RT::SavedSearch::Privacy(); and a type string, as produced
97 by RT::SavedSearch::Type().  The SavedSearches object will load the
98 searches belonging to that user or group that are of the type
99 specified.  If no type is specified, all the searches belonging to the
100 user/group will be loaded.  Repeated calls to the same object should DTRT.
101
102 =cut
103
104 sub LimitToPrivacy {
105     my $self = shift;
106     my $privacy = shift;
107     my $type = shift;
108
109     my $object = $self->_GetObject($privacy);
110
111     if ($object) {
112         $self->{'objects'} = [];
113         my @search_atts = $object->Attributes->Named('SavedSearch');
114         foreach my $att (@search_atts) {
115             my $search = RT::SavedSearch->new($self->CurrentUser);
116             $search->Load($privacy, $att->Id);
117             next if $type && $search->Type ne $type;
118             push(@{$self->{'objects'}}, $search);
119         }
120     } else {
121         $RT::Logger->error("Could not load object $privacy");
122     }
123 }
124
125 ### Accessor methods
126
127 =head2 Next
128
129 Returns the next object in the collection.
130
131 =cut
132
133 sub Next {
134     my $self = shift;
135     my $search = $self->{'objects'}->[$self->{'idx'}];
136     if ($search) {
137         $self->{'idx'}++;
138     } else {
139         # We have run out of objects; reset the counter.
140         $self->{'idx'} = 0;
141     }
142     return $search;
143 }
144
145 =head2 Count
146
147 Returns the number of search objects found.
148
149 =cut
150
151 sub Count {
152     my $self = shift;
153     return scalar @{$self->{'objects'}};
154 }
155
156 ### Internal methods
157
158 # _GetObject: helper routine to load the correct object whose parameters
159 #  have been passed.
160
161 sub _GetObject {
162     my $self = shift;
163     my $privacy = shift;
164
165     my ($obj_type, $obj_id) = split(/\-/, $privacy);
166     unless ($obj_type eq 'RT::User' || $obj_type eq 'RT::Group') {
167         $RT::Logger->error("Tried to load a search belonging to an $obj_type, which is neither a user nor a group");
168         return undef;
169     }
170
171     my $object;
172     eval "
173          require $obj_type;
174          \$object = $obj_type->new(\$self->CurrentUser);
175          \$object->Load($obj_id);
176     ";
177     unless (ref($object) eq $obj_type) {
178         $RT::Logger->error("Could not load object of type $obj_type with ID $obj_id");
179         return undef;
180     }
181     
182     # Do not allow the loading of a user object other than the current
183     # user, or of a group object of which the current user is not a member.
184
185     if ($obj_type eq 'RT::User'
186         && $object->Id != $self->CurrentUser->UserObj->Id()) {
187         $RT::Logger->error('Requested user ' . $object->Id 
188                            . 'is not current user');
189         return undef;
190     }
191     if ($obj_type eq 'RT::Group'
192         && !$object->HasMemberRecursively($self->CurrentUser->PrincipalObj)) {
193         $RT::Logger->error('Current user does not belong to requested group ' 
194                            . $object->Id);
195         return undef;
196     }
197
198     return $object;
199 }
200
201 eval "require RT::SavedSearches_Vendor";
202 die $@ if ($@ && $@ !~ qr{^Can't locate RT/SavedSearches_Vendor.pm});
203 eval "require RT::SavedSearches_Local";
204 die $@ if ($@ && $@ !~ qr{^Can't locate RT/SavedSearches_Local.pm});
205
206 1;