1 # BEGIN BPS TAGGED BLOCK {{{
5 # This software is Copyright (c) 1996-2007 Best Practical Solutions, LLC
6 # <jesse@bestpractical.com>
8 # (Except where explicitly superseded by other copyright notices)
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
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA
26 # 02110-1301 or visit their web page on the internet at
27 # http://www.gnu.org/copyleft/gpl.html.
30 # CONTRIBUTION SUBMISSION POLICY:
32 # (The following paragraph is not intended to limit the rights granted
33 # to you to modify and distribute this software under the terms of
34 # the GNU General Public License and is only of importance to you if
35 # you choose to contribute your changes and enhancements to the
36 # community by submitting them to Best Practical Solutions, LLC.)
38 # By intentionally submitting any modifications, corrections or
39 # derivatives to this work, or any other work intended for use with
40 # Request Tracker, to Best Practical Solutions, LLC, you confirm that
41 # you are the copyright holder for those contributions and you grant
42 # Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
43 # royalty-free, perpetual, license to use, copy, create derivative
44 # works based on those contributions, and sublicense and distribute
45 # those contributions and any derivatives thereof.
47 # END BPS TAGGED BLOCK }}}
50 RT::SavedSearch - an API for saving and retrieving search form values.
58 SavedSearch is an object that can belong to either an RT::User or an
59 RT::Group. It consists of an ID, a description, and a number of
66 use_ok(RT::SavedSearch);
68 # Real tests are in lib/t/20savedsearch.t
74 package RT::SavedSearch;
81 use base qw/RT::Base/;
85 my $class = ref($proto) || $proto;
88 bless ($self, $class);
89 $self->CurrentUser(@_);
95 Takes a privacy specification, an object ID, and a search ID. Loads
96 the given search ID if it belongs to the stated user or group.
97 Returns a tuple of status and message, where status is true on
104 my ($privacy, $id) = @_;
105 my $object = $self->_GetObject($privacy);
108 $self->{'Attribute'} = $object->Attributes->WithId($id);
109 if ($self->{'Attribute'}->Id) {
110 $self->{'Id'} = $self->{'Attribute'}->Id;
111 $self->{'Privacy'} = $privacy;
112 $self->{'Type'} = $self->{'Attribute'}->SubValue('SearchType');
113 return (1, $self->loc("Loaded search [_1]", $self->Name));
115 $RT::Logger->error("Could not load attribute " . $id
116 . " for object " . $privacy);
117 return (0, $self->loc("Search attribute load failure"));
120 $RT::Logger->warning("Could not load object $privacy when loading search");
121 return (0, $self->loc("Could not load object for [_1]", $privacy));
128 Takes a privacy, an optional type, a name, and a hashref containing the
129 search parameters. Saves the given parameters to the appropriate user/
130 group object, and loads the resulting search. Returns a tuple of status
131 and message, where status is true on success. Defaults are:
135 SearchParams: (empty hash)
141 my %args = ('Privacy' => 'RT::User-' . $self->CurrentUser->Id,
143 'Name' => 'new search',
144 'SearchParams' => {},
146 my $privacy = $args{'Privacy'};
147 my $type = $args{'Type'};
148 my $name = $args{'Name'};
149 my %params = %{$args{'SearchParams'}};
151 $params{'SearchType'} = $type;
152 my $object = $self->_GetObject($privacy);
154 return (0, $self->loc("Failed to load object for [_1]", $privacy))
157 if ( $object->isa('RT::System') ) {
158 return ( 0, $self->loc("No permission to save system-wide searches") )
159 unless $self->CurrentUser->HasRight(
160 Object => $RT::System,
165 my ( $att_id, $att_msg ) = $object->AddAttribute(
166 'Name' => 'SavedSearch',
167 'Description' => $name,
168 'Content' => \%params
171 $self->{'Attribute'} = $object->Attributes->WithId($att_id);
172 $self->{'Id'} = $att_id;
173 $self->{'Privacy'} = $privacy;
174 $self->{'Type'} = $type;
175 return ( 1, $self->loc( "Saved search [_1]", $name ) );
178 $RT::Logger->error("SavedSearch save failure: $att_msg");
179 return ( 0, $self->loc("Failed to create search attribute") );
185 Updates the parameters of an existing search. Takes the arguments
186 "Name" and "SearchParams"; SearchParams should be a hashref containing
187 the new parameters of the search. If Name is not specified, the name
194 my %args = ('Name' => '',
195 'SearchParams' => {},
198 return(0, $self->loc("No search loaded")) unless $self->Id;
199 return(0, $self->loc("Could not load search attribute"))
200 unless $self->{'Attribute'}->Id;
201 my ($status, $msg) = $self->{'Attribute'}->SetSubValues(%{$args{'SearchParams'}});
202 if ($status && $args{'Name'}) {
203 ($status, $msg) = $self->{'Attribute'}->SetDescription($args{'Name'});
205 return ($status, $self->loc("Search update: [_1]", $msg));
210 Deletes the existing search. Returns a tuple of status and message,
211 where status is true upon success.
218 my ($status, $msg) = $self->{'Attribute'}->Delete;
220 return (1, $self->loc("Deleted search"));
222 return (0, $self->loc("Delete failed: [_1]", $msg));
231 Returns the name of the search.
237 return unless ref($self->{'Attribute'}) eq 'RT::Attribute';
238 return $self->{'Attribute'}->Description();
243 Returns the given named parameter of the search, e.g. 'Query', 'Format'.
250 return unless ref($self->{'Attribute'}) eq 'RT::Attribute';
251 return $self->{'Attribute'}->SubValue($param);
256 Returns the numerical id of this search.
262 return $self->{'Id'};
267 Returns the principal object to whom this search belongs, in a string
268 "<class>-<id>", e.g. "RT::Group-16".
274 return $self->{'Privacy'};
279 Returns the type of this search, e.g. 'Ticket'. Useful for denoting the
280 saved searches that are relevant to a particular search page.
286 return $self->{'Type'};
291 sub _load_privacy_object {
292 my ($self, $obj_type, $obj_id) = @_;
293 if ( $obj_type eq 'RT::User' && $obj_id == $self->CurrentUser->Id) {
294 return $self->CurrentUser->UserObj;
296 elsif ($obj_type eq 'RT::Group') {
297 my $group = RT::Group->new($self->CurrentUser);
298 $group->Load($obj_id);
301 elsif ($obj_type eq 'RT::System') {
302 return RT::System->new($self->CurrentUser);
305 $RT::Logger->error("Tried to load a search belonging to an $obj_type, which is neither a user nor a group");
309 # _GetObject: helper routine to load the correct object whose parameters
316 my ($obj_type, $obj_id) = split(/\-/, $privacy);
318 my $object = $self->_load_privacy_object($obj_type, $obj_id);
320 unless (ref($object) eq $obj_type) {
321 $RT::Logger->error("Could not load object of type $obj_type with ID $obj_id");
325 # Do not allow the loading of a user object other than the current
326 # user, or of a group object of which the current user is not a member.
328 if ($obj_type eq 'RT::User'
329 && $object->Id != $self->CurrentUser->UserObj->Id()) {
330 $RT::Logger->debug("Permission denied for user other than self");
333 if ($obj_type eq 'RT::Group' &&
334 !$object->HasMemberRecursively($self->CurrentUser->PrincipalObj)) {
335 $RT::Logger->debug("Permission denied, ".$self->CurrentUser->Name.
336 " is not a member of group");
343 eval "require RT::SavedSearch_Vendor";
344 die $@ if ($@ && $@ !~ qr{^Can't locate RT/SavedSearch_Vendor.pm});
345 eval "require RT::SavedSearch_Local";
346 die $@ if ($@ && $@ !~ qr{^Can't locate RT/SavedSearch_Local.pm});