From d4d0590bef31071e8809ec046717444b95b3f30a Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 15 Oct 2005 09:11:20 +0000 Subject: import rt 3.4.4 --- rt/lib/RT/SavedSearch.pm | 327 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 327 insertions(+) create mode 100644 rt/lib/RT/SavedSearch.pm (limited to 'rt/lib/RT/SavedSearch.pm') diff --git a/rt/lib/RT/SavedSearch.pm b/rt/lib/RT/SavedSearch.pm new file mode 100644 index 000000000..65411a7b2 --- /dev/null +++ b/rt/lib/RT/SavedSearch.pm @@ -0,0 +1,327 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC +# +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +=head1 NAME + + RT::SavedSearch - an API for saving and retrieving search form values. + +=head1 SYNOPSIS + + use RT::SavedSearch + +=head1 DESCRIPTION + + SavedSearch is an object that can belong to either an RT::User or an + RT::Group. It consists of an ID, a description, and a number of + search parameters. + +=head1 METHODS + +=begin testing + +use_ok(RT::SavedSearch); + +# Real tests are in lib/t/20savedsearch.t + +=end testing + +=cut + +package RT::SavedSearch; + +use RT::Base; +use RT::Attribute; + +use strict; +use vars qw/@ISA/; +@ISA = qw/RT::Base/; + +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = {}; + $self->{'Id'} = 0; + bless ($self, $class); + $self->CurrentUser(@_); + return $self; +} + +=head2 Load + +Takes a privacy specification, an object ID, and a search ID. Loads +the given search ID if it belongs to the stated user or group. +Returns a tuple of status and message, where status is true on +success. + +=cut + +sub Load { + my $self = shift; + my ($privacy, $id) = @_; + my $object = $self->_GetObject($privacy); + + if ($object) { + $self->{'Attribute'} = $object->Attributes->WithId($id); + if ($self->{'Attribute'}->Id) { + $self->{'Id'} = $self->{'Attribute'}->Id; + $self->{'Privacy'} = $privacy; + $self->{'Type'} = $self->{'Attribute'}->SubValue('SearchType'); + return (1, $self->loc("Loaded search [_1]", $self->Name)); + } else { + $RT::Logger->error("Could not load attribute " . $id + . " for object " . $privacy); + return (0, $self->loc("Search attribute load failure")); + } + } else { + $RT::Logger->error("Could not load object $privacy when loading search"); + return (0, $self->loc("Could not load object for [_1]", $privacy)); + } + +} + +=head2 Save + +Takes a privacy, an optional type, a name, and a hashref containing the +search parameters. Saves the given parameters to the appropriate user/ +group object, and loads the resulting search. Returns a tuple of status +and message, where status is true on success. Defaults are: + Privacy: undef + Type: Ticket + Name: "new search" + SearchParams: (empty hash) + +=cut + +sub Save { + my $self = shift; + my %args = ('Privacy' => 'RT::User-' . $self->CurrentUser->Id, + 'Type' => 'Ticket', + 'Name' => 'new search', + 'SearchParams' => {}, + @_); + my $privacy = $args{'Privacy'}; + my $type = $args{'Type'}; + my $name = $args{'Name'}; + my %params = %{$args{'SearchParams'}}; + + $params{'SearchType'} = $type; + my $object = $self->_GetObject($privacy); + if ($object) { + my ($att_id, $att_msg) = $object->AddAttribute( + 'Name' => 'SavedSearch', + 'Description' => $name, + 'Content' => \%params); + if ($att_id) { + $self->{'Attribute'} = $object->Attributes->WithId($att_id); + $self->{'Id'} = $att_id; + $self->{'Privacy'} = $privacy; + $self->{'Type'} = $type; + return (1, $self->loc("Saved search [_1]", $name)); + } else { + $RT::Logger->error("SavedSearch save failure: $att_msg"); + return (0, $self->loc("Failed to create search attribute")); + } + } else { + return (0, $self->loc("Failed to load object for [_1]", $privacy)); + } +} + +=head2 Update + +Updates the parameters of an existing search. Takes the arguments +"Name" and "SearchParams"; SearchParams should be a hashref containing +the new parameters of the search. If Name is not specified, the name +will not be changed. + +=cut + +sub Update { + my $self = shift; + my %args = ('Name' => '', + 'SearchParams' => {}, + @_); + + return(0, $self->loc("No search loaded")) unless $self->Id; + return(0, $self->loc("Could not load search attribute")) + unless $self->{'Attribute'}->Id; + my ($status, $msg) = $self->{'Attribute'}->SetSubValues(%{$args{'SearchParams'}}); + if ($status && $args{'Name'}) { + ($status, $msg) = $self->{'Attribute'}->SetDescription($args{'Name'}); + } + return ($status, $self->loc("Search update: [_1]", $msg)); +} + +=head2 Delete + +Deletes the existing search. Returns a tuple of status and message, +where status is true upon success. + +=cut + +sub Delete { + my $self = shift; + + my ($status, $msg) = $self->{'Attribute'}->Delete; + if ($status) { + return (1, $self->loc("Deleted search")); + } else { + return (0, $self->loc("Delete failed: [_1]", $msg)); + } +} + + +### Accessor methods + +=head2 Name + +Returns the name of the search. + +=cut + +sub Name { + my $self = shift; + return unless ref($self->{'Attribute'}) eq 'RT::Attribute'; + return $self->{'Attribute'}->Description(); +} + +=head2 GetParameter + +Returns the given named parameter of the search, e.g. 'Query', 'Format'. + +=cut + +sub GetParameter { + my $self = shift; + my $param = shift; + return unless ref($self->{'Attribute'}) eq 'RT::Attribute'; + return $self->{'Attribute'}->SubValue($param); +} + +=head2 Id + +Returns the numerical id of this search. + +=cut + +sub Id { + my $self = shift; + return $self->{'Id'}; +} + +=head2 Privacy + +Returns the principal object to whom this search belongs, in a string +"-", e.g. "RT::Group-16". + +=cut + +sub Privacy { + my $self = shift; + return $self->{'Privacy'}; +} + +=head2 Type + +Returns the type of this search, e.g. 'Ticket'. Useful for denoting the +saved searches that are relevant to a particular search page. + +=cut + +sub Type { + my $self = shift; + return $self->{'Type'}; +} + +### Internal methods + +# _GetObject: helper routine to load the correct object whose parameters +# have been passed. + +sub _GetObject { + my $self = shift; + my $privacy = shift; + + my ($obj_type, $obj_id) = split(/\-/, $privacy); + unless ($obj_type eq 'RT::User' || $obj_type eq 'RT::Group') { + $RT::Logger->error("Tried to load a search belonging to an $obj_type, which is neither a user nor a group"); + return undef; + } + + my $object; + eval " + require $obj_type; + \$object = $obj_type->new(\$self->CurrentUser); + \$object->Load(\$obj_id); + "; + unless (ref($object) eq $obj_type) { + $RT::Logger->error("Could not load object of type $obj_type with ID $obj_id"); + return undef; + } + + # Do not allow the loading of a user object other than the current + # user, or of a group object of which the current user is not a member. + + if ($obj_type eq 'RT::User' + && $object->Id != $self->CurrentUser->UserObj->Id()) { + $RT::Logger->debug("Permission denied for user other than self"); + return undef; + } + if ($obj_type eq 'RT::Group' && + !$object->HasMemberRecursively($self->CurrentUser->PrincipalObj)) { + $RT::Logger->debug("Permission denied, ".$self->CurrentUser->Name. + " is not a member of group"); + return undef; + } + + return $object; +} + +eval "require RT::SavedSearch_Vendor"; +die $@ if ($@ && $@ !~ qr{^Can't locate RT/SavedSearch_Vendor.pm}); +eval "require RT::SavedSearch_Local"; +die $@ if ($@ && $@ !~ qr{^Can't locate RT/SavedSearch_Local.pm}); + +1; -- cgit v1.2.1