]>
Commit | Line | Data |
---|---|---|
84fb5b46 MKG |
1 | %# BEGIN BPS TAGGED BLOCK {{{ |
2 | %# | |
3 | %# COPYRIGHT: | |
4 | %# | |
320f0092 | 5 | %# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC |
84fb5b46 MKG |
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 | %# REST/1.0/search/dhandler | |
49 | %# | |
320f0092 MKG |
50 | <%ARGS> |
51 | $query | |
52 | $format => undef | |
53 | $orderby => undef | |
54 | $fields => undef | |
55 | </%ARGS> | |
84fb5b46 | 56 | <%INIT> |
320f0092 MKG |
57 | my $type = $m->dhandler_arg; |
58 | my ( $status, $output ); | |
59 | ||
60 | if ( $type =~ /^(ticket|queue|user|group)$/i ) { | |
61 | $status = "200 Ok"; | |
62 | $output = ''; | |
63 | my $type = lc $1; | |
64 | ||
65 | if ( | |
66 | $type eq 'user' | |
67 | && !$session{CurrentUser}->HasRight( | |
68 | Object => $RT::System, | |
69 | Right => 'AdminUsers', | |
70 | ) | |
71 | ) | |
72 | { | |
73 | ||
74 | $status = "403 Forbidden"; | |
75 | $output = "Permission denied"; | |
76 | goto OUTPUT; | |
77 | } | |
78 | ||
79 | my $class = 'RT::' . ucfirst $type . 's'; | |
80 | my $objects = $class->new( $session{CurrentUser} ); | |
81 | ||
82 | # Parse and validate any field specifications. | |
83 | require RT::Interface::REST; | |
84 | my $field = RT::Interface::REST->field_spec; | |
85 | my ( %fields, @fields ); | |
86 | if ($fields) { | |
87 | $format ||= "l"; | |
88 | unless ( $fields =~ /^(?:$field,)*$field$/ ) { | |
89 | $status = "400 Bad Request"; | |
90 | $output = "Invalid field specification: $fields"; | |
91 | goto OUTPUT; | |
92 | } | |
93 | @fields = map lc, split /\s*,\s*/, $fields; | |
94 | @fields{@fields} = (); | |
95 | unless ( exists $fields{id} ) { | |
96 | unshift @fields, "id"; | |
97 | $fields{id} = (); | |
98 | } | |
99 | } | |
100 | ||
101 | $format ||= "s"; | |
102 | if ( $format !~ /^[isl]$/ ) { | |
103 | $status = "400 Bad request"; | |
104 | $output = "Unknown listing format: $format. (Use i, s, or l.)\n"; | |
105 | goto OUTPUT; | |
106 | } | |
107 | ||
108 | my ( $n, $s ); | |
109 | $n = 0; | |
110 | my @output; | |
111 | ||
112 | ||
113 | if ( $type eq 'group' ) { | |
114 | $objects->LimitToUserDefinedGroups; | |
115 | } | |
116 | ||
117 | if ( defined $query && length $query ) { | |
118 | if ( $type eq 'ticket' ) { | |
119 | my ( $n, $s ); | |
120 | eval { ( $n, $s ) = $objects->FromSQL($query); }; | |
121 | if ( $@ || $n == 0 ) { | |
122 | $s ||= $@; | |
123 | $status = "400 Bad request"; | |
124 | $output = "Invalid query: '$s'.\n"; | |
125 | goto OUTPUT; | |
126 | } | |
127 | } | |
128 | else { | |
129 | require Text::ParseWords; | |
130 | my ( $field, $op, $value ) = Text::ParseWords::shellwords($query); | |
131 | if ( $op !~ | |
132 | /^(?:[!<>]?=|[<>]|(NOT )?LIKE|STARTSWITH|ENDSWITH|MATCHES)$/i ) | |
133 | { | |
134 | $status = "400 Bad Request"; | |
135 | $output = "Invalid operator specification: $op"; | |
136 | goto OUTPUT; | |
137 | } | |
138 | ||
139 | if ( ! $search_whitelist{$type}{lc $field} ) { | |
140 | $status = "400 Bad Request"; | |
141 | $output = "Invalid field specification: $field"; | |
142 | goto OUTPUT; | |
143 | } | |
144 | ||
145 | ||
146 | if ( $field && $op && defined $value ) { | |
147 | if ( $field eq 'Disabled' ) { | |
148 | if ($value) { | |
149 | if ( $type eq 'queue' ) { | |
150 | $objects->FindAllRows; | |
151 | $objects->Limit( | |
152 | FIELD => $field, | |
153 | OPERATOR => uc $op, | |
154 | VALUE => $value | |
155 | ); | |
156 | } | |
157 | else { | |
158 | $objects->LimitToDeleted; | |
159 | } | |
160 | } | |
161 | else { | |
162 | if ( $type eq 'queue' ) { | |
163 | $objects->UnLimit; | |
164 | } | |
165 | else { | |
166 | $objects->LimitToEnabled; | |
167 | } | |
168 | } | |
169 | } | |
170 | else { | |
171 | $objects->Limit( | |
172 | FIELD => $field, | |
173 | OPERATOR => uc $op, | |
174 | VALUE => $value, | |
175 | CASESENSITIVE => 0, | |
176 | ); | |
177 | } | |
178 | } | |
179 | else { | |
180 | $output = "Invalid query specification: $query"; | |
181 | goto OUTPUT; | |
182 | } | |
183 | } | |
184 | } | |
185 | else { | |
186 | if ( $type eq 'queue' ) { | |
187 | $objects->UnLimit; | |
188 | } | |
189 | elsif ( $type eq 'user' ) { | |
190 | $objects->LimitToPrivileged; | |
191 | } | |
192 | } | |
193 | ||
194 | if ($orderby) { | |
195 | my ( $order, $field ) = $orderby =~ /^([\+\-])?(.+)/; | |
196 | $order = $order && $order eq '-' ? 'DESC' : 'ASC'; | |
197 | $objects->OrderBy( FIELD => $field, ORDER => $order ); | |
198 | } | |
199 | ||
200 | while ( my $object = $objects->Next ) { | |
201 | next if $type eq 'user' && ( $object->id == RT->SystemUser->id || $object->id == RT->Nobody->id ); | |
202 | $n++; | |
203 | ||
204 | my $id = $object->Id; | |
205 | if ( $format eq "i" ) { | |
206 | $output .= "$type/" . $id . "\n"; | |
207 | } | |
208 | elsif ( $format eq "s" ) { | |
209 | if ($fields) { | |
210 | my $result = $m->comp( | |
211 | "/REST/1.0/Forms/$type/default", | |
212 | id => $id, | |
213 | format => $format, | |
214 | fields => \%fields | |
215 | ); | |
216 | my ( $notes, $order, $key_values, $errors ) = @$result; | |
217 | ||
218 | # If it's the first time through, add our header | |
219 | if ( $n == 1 ) { | |
220 | $output .= join( "\t", @$order ) . "\n"; | |
221 | } | |
222 | ||
223 | # Cut off the annoying $type/ before the id; | |
224 | $key_values->{'id'} = $id; | |
225 | $output .= join( | |
226 | "\t", | |
227 | map { | |
228 | ref $key_values->{$_} eq 'ARRAY' | |
229 | ? join( ', ', @{ $key_values->{$_} } ) | |
230 | : $key_values->{$_} | |
231 | } @$order | |
232 | ) . "\n"; | |
233 | } | |
234 | else { | |
235 | if ( $type eq 'ticket' ) { | |
236 | $output .= $object->Id . ": " . $object->Subject . "\n"; | |
237 | } | |
238 | else { | |
239 | $output .= $object->Id . ": " . $object->Name . "\n"; | |
240 | } | |
241 | } | |
242 | } | |
243 | else { | |
244 | my $d = $m->comp( | |
245 | "/REST/1.0/Forms/$type/default", | |
246 | id => $id, | |
247 | format => $format, | |
248 | fields => \%fields | |
249 | ); | |
250 | my ( $c, $o, $k, $e ) = @$d; | |
251 | push @output, [ $c, $o, $k ]; | |
252 | } | |
253 | } | |
254 | if ( $n == 0 && $format ne "i" ) { | |
255 | $output = "No matching results.\n"; | |
256 | } | |
257 | ||
258 | $output = form_compose( \@output ) if @output; | |
259 | } | |
260 | else { | |
261 | $status = "500 Server Error"; | |
262 | $output = "Unsupported object type."; | |
263 | goto OUTPUT; | |
264 | } | |
265 | ||
266 | OUTPUT: | |
267 | $m->out("RT/". $RT::VERSION . " " . $status ."\n\n"); | |
268 | $m->out($output ); | |
84fb5b46 | 269 | </%INIT> |
84fb5b46 | 270 | |
320f0092 MKG |
271 | <%ONCE> |
272 | my %search_whitelist = ( | |
273 | queue => { | |
274 | map { lc $_ => 1 } | |
275 | grep { $RT::Record::_TABLE_ATTR->{'RT::Queue'}{$_}{read} } | |
276 | keys %{ $RT::Record::_TABLE_ATTR->{'RT::Queue'} } | |
277 | }, | |
278 | user => { | |
279 | disabled => 1, | |
280 | map { lc $_ => 1 } | |
281 | grep { $RT::Record::_TABLE_ATTR->{'RT::User'}{$_}{read} } | |
282 | keys %{ $RT::Record::_TABLE_ATTR->{'RT::User'} } | |
283 | }, | |
284 | group => { | |
285 | disabled => 1, | |
286 | map { lc $_ => 1 } | |
287 | grep { $RT::Record::_TABLE_ATTR->{'RT::Group'}{$_}{read} } | |
288 | keys %{ $RT::Record::_TABLE_ATTR->{'RT::Group'} } | |
289 | } | |
290 | ); | |
291 | ||
292 | </%ONCE> | |
293 |