rt 4.2.14 (#13852)
[freeside.git] / rt / share / html / Search / Elements / EditSearches
1 %# BEGIN BPS TAGGED BLOCK {{{
2 %#
3 %# COPYRIGHT:
4 %#
5 %# This software is Copyright (c) 1996-2017 Best Practical Solutions, LLC
6 %#                                          <sales@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., 51 Franklin Street, Fifth Floor, Boston, MA
26 %# 02110-1301 or visit their web page on the internet at
27 %# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
28 %#
29 %#
30 %# CONTRIBUTION SUBMISSION POLICY:
31 %#
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.)
37 %#
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.
46 %#
47 %# END BPS TAGGED BLOCK }}}
48 <div class="edit-saved-searches">
49 <&| /Widgets/TitleBox, title => loc($Title)&>
50
51 %# Hide all the save functionality if the user shouldn't see it.
52 % if ( $can_modify ) {
53 <span class="label"><&|/l&>Privacy</&>:</span>
54 <& SelectSearchObject, Name => 'SavedSearchOwner', Objects => \@Objects, Object => ( $Object && $Object->id ) ? $Object->Object : '' &>
55 <br />
56 <span class="label"><&|/l&>Description</&>:</span>
57 <input size="25" name="SavedSearchDescription" value="<% $Description || '' %>" />
58
59 % if ($Id ne 'new') {
60 <nobr>
61 % if ( $Dirty ) {
62 <input type="submit" class="button" name="SavedSearchRevert" value="<%loc('Revert')%>" />
63 % }
64 <input type="submit" class="button" name="SavedSearchDelete" value="<%loc('Delete')%>" />
65 % if ( $AllowCopy ) {
66 <input type="submit" class="button" name="SavedSearchCopy"   value="<%loc('Save as New')%>" />
67 % }
68 </nobr>
69 % }
70 % if ( $Object && $Object->Id && $Object->CurrentUserHasRight('update') ) {
71 <input type="submit" class="button" id="SavedSearchSave" name="SavedSearchSave"   value="<%loc('Update')%>" />
72 % } elsif ( !$Object ) {
73 <input type="submit" class="button" id="SavedSearchSave" name="SavedSearchSave"   value="<%loc('Save')%>" />
74 %}
75 % }
76 <br />
77 <hr />
78 <span class="label"><&|/l&>Load saved search</&>:</span>
79 <& SelectSearchesForObjects, Name => 'SavedSearchLoad', Objects => \@Objects, SearchType => $Type &>
80 <input type="submit" value="<% loc('Load') %>" id="SavedSearchLoadSubmit" name="SavedSearchLoadSubmit" class="button" />
81
82 </&>
83 </div>
84 <%INIT>
85 return unless $session{'CurrentUser'}->HasRight(
86     Right  => 'LoadSavedSearch',
87     Object => $RT::System,
88 );
89
90 my $can_modify = $session{'CurrentUser'}->HasRight(
91     Right  => 'CreateSavedSearch',
92     Object => $RT::System,
93 );
94
95 use RT::SavedSearch;
96 my @Objects = RT::SavedSearch->new($session{CurrentUser})->_PrivacyObjects;
97 push @Objects, RT::System->new( $session{'CurrentUser'} )
98     if $session{'CurrentUser'}->HasRight( Object=> $RT::System,
99                                           Right => 'SuperUser' );
100
101 my $is_dirty = sub {
102     my %arg = (
103         Query       => {},
104         SavedSearch => {},
105         SearchFields => [qw(Query Format OrderBy Order RowsPerPage)],
106         @_
107     );
108
109     my $obj  = $arg{'SavedSearch'}->{'Object'};
110     return 0 unless $obj && $obj->id;
111
112     foreach( @{ $arg{'SearchFields'} } ) {
113         return 1 if $obj->SubValue( $_ ) ne $arg{'Query'}->{$_};
114     }
115
116     return 0;
117 };
118
119 # If we're modifying an old query, check if it's been changed
120 my $Dirty = $is_dirty->(
121     Query       => $CurrentSearch,
122     SavedSearch => { Id => $Id, Object => $Object, Description => $Description },
123     SearchFields => \@SearchFields,
124 );
125
126 </%INIT>
127
128 <%ARGS>
129 $Id            => 'new'
130 $Object        => undef
131 $Type          => 'Ticket'
132 $Description   => ''
133 $CurrentSearch => {}
134 @SearchFields   => ()
135 $AllowCopy     => 1
136 $Title         => loc('Saved searches')
137 </%ARGS>
138
139 <%METHOD Init>
140 <%ARGS>
141 $Query       => {}
142 $SavedSearch => {}
143 @SearchFields => qw(Query Format OrderBy Order RowsPerPage)
144 </%ARGS>
145 <%INIT>
146
147 $SavedSearch->{'Id'}          = ( $ARGS{Type} && $ARGS{Type} eq 'Chart' ?
148 $ARGS{'SavedChartSearchId'} : $ARGS{'SavedSearchId'} ) || 'new';
149 $SavedSearch->{'Description'} = $ARGS{'SavedSearchDescription'} || '';
150 $SavedSearch->{'Privacy'}     = $ARGS{'SavedSearchOwner'}       || undef;
151
152 my @results;
153
154 if ( $ARGS{'SavedSearchRevert'} ) {
155     $ARGS{'SavedSearchLoad'} = $SavedSearch->{'Id'};
156 }
157
158 if ( $ARGS{'SavedSearchLoad'} ) {
159     my ($container, $id ) = _parse_saved_search ($ARGS{'SavedSearchLoad'});
160     if ( $container ) {
161         my $search = RT::Attribute->new( $session{'CurrentUser'} );
162         $search->Load( $id );
163         $SavedSearch->{'Id'}          = $ARGS{'SavedSearchLoad'};
164         $SavedSearch->{'Object'}      = $search;
165         $SavedSearch->{'Description'} = $search->Description;
166         $Query->{$_} = $search->SubValue($_) foreach @SearchFields;
167
168         if ( $ARGS{'SavedSearchRevert'} ) {
169             push @results, loc('Loaded original "[_1]" saved search', $SavedSearch->{'Description'} );
170         } else {
171             push @results, loc('Loaded saved search "[_1]"', $SavedSearch->{'Description'} );
172         }
173     }
174     else {
175         push @results, loc( 'Can not load saved search "[_1]"',
176                 $ARGS{'SavedSearchLoad'} );
177         return @results;
178     }
179 }
180 elsif ( $ARGS{'SavedSearchDelete'} ) {
181     # We set $SearchId to 'new' above already, so peek into the %ARGS
182     my ($container, $id) = _parse_saved_search( $SavedSearch->{'Id'} );
183     if ( $container && $container->id ) {
184         # We have the object the entry is an attribute on; delete the entry...
185         my ($val, $msg) = $container->Attributes->DeleteEntry( Name => 'SavedSearch', id => $id );
186         unless ( $val ) {
187             push @results, $msg;
188             return @results;
189         }
190     }
191     $SavedSearch->{'Id'}          = 'new';
192     $SavedSearch->{'Object'}      = undef;
193     $SavedSearch->{'Description'} = undef;
194     push @results, loc("Deleted saved search");
195 }
196 elsif ( $ARGS{'SavedSearchCopy'} ) {
197     my ($container, $id ) = _parse_saved_search( $ARGS{'SavedSearchId'} );
198     $SavedSearch->{'Object'} = RT::Attribute->new( $session{'CurrentUser'} );
199     $SavedSearch->{'Object'}->Load( $id );
200     if ( $ARGS{'SavedSearchDescription'} && $ARGS{'SavedSearchDescription'} ne $SavedSearch->{'Object'}->Description ) {
201         $SavedSearch->{'Description'} = $ARGS{'SavedSearchDescription'};
202     } else {
203         $SavedSearch->{'Description'} = loc( "[_1] copy", $SavedSearch->{'Object'}->Description );
204     }
205     $SavedSearch->{'Id'}          = 'new';
206     $SavedSearch->{'Object'}      = undef;
207 }
208
209 if ( $SavedSearch->{'Id'} && $SavedSearch->{'Id'} ne 'new'
210      && !$SavedSearch->{'Object'} )
211 {
212     my ($container, $id ) = _parse_saved_search( $ARGS{'SavedSearchId'} );
213     $SavedSearch->{'Object'} = RT::Attribute->new( $session{'CurrentUser'} );
214     $SavedSearch->{'Object'}->Load( $id );
215     $SavedSearch->{'Description'} ||= $SavedSearch->{'Object'}->Description;
216 }
217
218 return @results;
219
220 </%INIT>
221 </%METHOD>
222
223 <%METHOD Save>
224 <%ARGS>
225 $Query        => {}
226 $SavedSearch  => {}
227 @SearchFields => qw(Query Format OrderBy Order RowsPerPage)
228 </%ARGS>
229 <%INIT>
230
231 return unless $ARGS{'SavedSearchSave'} || $ARGS{'SavedSearchCopy'};
232
233 my @results;
234 my $obj  = $SavedSearch->{'Object'};
235 my $id   = $SavedSearch->{'Id'};
236 my $desc = $SavedSearch->{'Description'};
237 my $privacy = $SavedSearch->{'Privacy'};
238
239 my %params = map { $_ => $Query->{$_} } @SearchFields;
240 my ($new_obj_type, $new_obj_id) = split(/\-/, ($privacy || ''));
241
242 if ( $obj && $obj->id ) {
243     # permission check
244     if ($obj->Object->isa('RT::System')) {
245         unless ($session{'CurrentUser'}->HasRight( Object=> $RT::System, Right => 'SuperUser')) {
246             push @results, loc("No permission to save system-wide searches");
247             return @results;
248         }
249     }
250
251     $obj->SetSubValues( %params );
252     $obj->SetDescription( $desc );
253
254     my $obj_type = ref($obj->Object);
255     # We need to get current obj_id now, because when we change obj_type to
256     # RT::System, $obj->Object->Id returns 1, not the old one :(
257     my $obj_id = $obj->Object->Id;
258
259     if ( $new_obj_type && $new_obj_id ) {
260         my ($val, $msg);
261
262         # we need to check right before we change any of ObjectType and ObjectId, 
263         # or it will fail the 2nd change if we use SetObjectType and
264         # SetObjectId sequentially
265
266         if ( $obj->CurrentUserHasRight('update') ) {
267             if ( $new_obj_type ne $obj_type ) {
268                 ( $val, $msg ) = $obj->__Set(
269                     Field => 'ObjectType',
270                     Value => $new_obj_type,
271                 );
272                 push @results, loc( 'Unable to set privacy object: [_1]', $msg )
273                   unless ($val);
274             }
275             if ( $new_obj_id != $obj_id ) {
276                 ( $val, $msg ) = $obj->__Set(
277                     Field => 'ObjectId',
278                     Value => $new_obj_id,
279                 );
280                 push @results, loc( 'Unable to set privacy id: [_1]', $msg )
281                   unless ($val);
282             }
283         }
284         else {
285             # two loc are just for convenience so we don't need to
286             # write an extra i18n translation item
287             push @results,
288               loc( 'Unable to set privacy object or id: [_1]',
289                 loc('Permission Denied') )
290         }
291     } else {
292         push @results, loc('Unable to determine object type or id');
293     }
294     push @results, loc('Updated saved search "[_1]"', $desc);
295 }
296 elsif ( $id eq 'new' and defined $desc and length $desc ) {
297     my $saved_search = RT::SavedSearch->new( $session{'CurrentUser'} );
298     my ($status, $msg) = $saved_search->Save(
299         Privacy      => $privacy,
300         Name         => $desc,
301         Type         => $SavedSearch->{'Type'},
302         SearchParams => \%params,
303     );
304
305     if ( $status ) {
306         $SavedSearch->{'Object'} = RT::Attribute->new( $session{'CurrentUser'} );
307         $SavedSearch->{'Object'}->Load( $saved_search->Id );
308         # Build new SearchId
309         $SavedSearch->{'Id'} =
310                 ref( $session{'CurrentUser'}->UserObj ) . '-'
311                     . $session{'CurrentUser'}->UserObj->Id
312                     . '-SavedSearch-'
313                     . $SavedSearch->{'Object'}->Id;
314     }
315     else {
316         push @results, loc("Can't find a saved search to work with").': '.loc($msg);
317     }
318 }
319 elsif ( $id eq 'new' ) {
320     push @results, loc("Can't save a search without a Description");
321 }
322 else {
323     push @results, loc("Can't save this search");
324 }
325
326 return @results;
327
328 </%INIT>
329 </%METHOD>