eab9a1009ef58f706c091aa1e4e0b86f26abc7c6
[usit-rt.git] / lib / RT / CustomFields.pm
1 # BEGIN BPS TAGGED BLOCK {{{
2 #
3 # COPYRIGHT:
4 #
5 # This software is Copyright (c) 1996-2014 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
49 =head1 NAME
50
51   RT::CustomFields - a collection of RT CustomField objects
52
53 =head1 SYNOPSIS
54
55   use RT::CustomFields;
56
57 =head1 DESCRIPTION
58
59 =head1 METHODS
60
61
62
63 =cut
64
65
66 package RT::CustomFields;
67
68 use strict;
69 use warnings;
70
71 use base 'RT::SearchBuilder';
72
73 use RT::CustomField;
74
75 sub Table { 'CustomFields'}
76
77 sub _Init {
78     my $self = shift;
79
80   # By default, order by SortOrder
81   $self->OrderByCols(
82          { ALIAS => 'main',
83            FIELD => 'SortOrder',
84            ORDER => 'ASC' },
85          { ALIAS => 'main',
86            FIELD => 'Name',
87            ORDER => 'ASC' },
88          { ALIAS => 'main',
89            FIELD => 'id',
90            ORDER => 'ASC' },
91      );
92     $self->{'with_disabled_column'} = 1;
93
94     return ( $self->SUPER::_Init(@_) );
95 }
96
97 =head2 LimitToGrouping
98
99 Limits this collection object to custom fields which appear under a
100 specified grouping by calling L</Limit> for each CF name as appropriate.
101
102 Requires an L<RT::Record> object or class name as the first argument and
103 accepts a grouping name as the second.  If the grouping name is false
104 (usually via the empty string), limits to custom fields which appear in no
105 grouping.
106
107 I<Caveat:> While the record object or class name is used to find the
108 available groupings, no automatic limit is placed on the lookup type of
109 the custom fields.  It's highly suggested you limit the collection by
110 queue or another lookup type first.  This is already done for you if
111 you're creating the collection via the L</CustomFields> method on an
112 L<RT::Record> object.
113
114 =cut
115
116 sub LimitToGrouping {
117     my $self = shift;
118     my $obj = shift;
119     my $grouping = shift;
120
121     my $config = RT->Config->Get('CustomFieldGroupings');
122        $config = {} unless ref($config) eq 'HASH';
123        $config = $config->{ref($obj) || $obj} || [];
124     my %h = ref $config eq "ARRAY" ? @{$config} : %{$config};
125
126     if ( $grouping ) {
127         my $list = $h{$grouping};
128         unless ( $list and ref($list) eq 'ARRAY' and @$list ) {
129             return $self->Limit( FIELD => 'id', VALUE => 0, ENTRYAGGREGATOR => 'AND' );
130         }
131         foreach ( @$list ) {
132             $self->Limit( FIELD => 'Name', VALUE => $_, CASESENSITIVE => 0 );
133         }
134     } else {
135         my @list = map {@$_} grep defined && ref($_) eq 'ARRAY',
136             values %h;
137
138         return unless @list;
139         foreach ( @list ) {
140             $self->Limit(
141                 FIELD => 'Name',
142                 OPERATOR => '!=',
143                 VALUE => $_,
144                 ENTRYAGGREGATOR => 'AND',
145                 CASESENSITIVE => 0,
146             );
147         }
148
149     }
150     return;
151 }
152
153
154 =head2 LimitToLookupType
155
156 Takes LookupType and limits collection.
157
158 =cut
159
160 sub LimitToLookupType  {
161     my $self = shift;
162     my $lookup = shift;
163
164     $self->Limit( FIELD => 'LookupType', VALUE => "$lookup" );
165 }
166
167 =head2 LimitToChildType
168
169 Takes partial LookupType and limits collection to records
170 where LookupType is equal or ends with the value.
171
172 =cut
173
174 sub LimitToChildType  {
175     my $self = shift;
176     my $lookup = shift;
177
178     $self->Limit( FIELD => 'LookupType', VALUE => "$lookup" );
179     $self->Limit( FIELD => 'LookupType', ENDSWITH => "$lookup" );
180 }
181
182
183 =head2 LimitToParentType
184
185 Takes partial LookupType and limits collection to records
186 where LookupType is equal or starts with the value.
187
188 =cut
189
190 sub LimitToParentType  {
191     my $self = shift;
192     my $lookup = shift;
193
194     $self->Limit( FIELD => 'LookupType', VALUE => "$lookup" );
195     $self->Limit( FIELD => 'LookupType', STARTSWITH => "$lookup" );
196 }
197
198 =head2 LimitToObjectId
199
200 Takes an ObjectId and limits the collection to CFs applied to said object.
201
202 When called multiple times the ObjectId limits are joined with OR.
203
204 =cut
205
206 sub LimitToObjectId {
207     my $self = shift;
208     my $id = shift;
209     $self->Limit(
210         ALIAS           => $self->_OCFAlias,
211         FIELD           => 'ObjectId',
212         OPERATOR        => '=',
213         VALUE           => $id || 0,
214         ENTRYAGGREGATOR => 'OR'
215     );
216 }
217
218 =head2 LimitToGlobalOrObjectId
219
220 Takes list of object IDs and limits collection to custom
221 fields that are added to these objects or globally.
222
223 =cut
224
225 sub LimitToGlobalOrObjectId {
226     my $self = shift;
227     my $global_only = 1;
228
229
230     foreach my $id (@_) {
231         $self->LimitToObjectId($id);
232         $global_only = 0 if $id;
233     }
234
235     $self->LimitToObjectId(0) unless $global_only;
236 }
237
238 =head2 LimitToNotAdded
239
240 Takes either list of object ids or nothing. Limits collection
241 to custom fields to listed objects or any corespondingly. Use
242 zero to mean global.
243
244 =cut
245
246 sub LimitToNotAdded {
247     my $self = shift;
248     return RT::ObjectCustomFields->new( $self->CurrentUser )
249         ->LimitTargetToNotAdded( $self => @_ );
250 }
251
252 =head2 LimitToAdded
253
254 Limits collection to custom fields to listed objects or any corespondingly. Use
255 zero to mean global.
256
257 =cut
258
259 sub LimitToAdded {
260     my $self = shift;
261     return RT::ObjectCustomFields->new( $self->CurrentUser )
262         ->LimitTargetToAdded( $self => @_ );
263 }
264
265 =head2 LimitToGlobalOrQueue QUEUEID
266
267 Limits the set of custom fields found to global custom fields or those
268 tied to the queue C<QUEUEID>, similar to L</LimitToGlobalOrObjectId>.
269
270 Note that this will cause the collection to only return ticket CFs.
271
272 =cut
273
274 sub LimitToGlobalOrQueue {
275     my $self = shift;
276     my $queue = shift;
277     $self->LimitToGlobalOrObjectId( $queue );
278     $self->LimitToLookupType( 'RT::Queue-RT::Ticket' );
279 }
280
281
282 =head2 LimitToQueue QUEUEID
283
284 Takes a numeric C<QUEUEID>, and limits the Custom Field collection to
285 those only applied directly to it; this limit is OR'd with other
286 L</LimitToQueue> and L</LimitToGlobal> limits.
287
288 Note that this will cause the collection to only return ticket CFs.
289
290 =cut
291
292 sub LimitToQueue  {
293    my $self = shift;
294    my $queue = shift;
295
296    $self->Limit (ALIAS => $self->_OCFAlias,
297                  ENTRYAGGREGATOR => 'OR',
298                  FIELD => 'ObjectId',
299                  VALUE => "$queue")
300        if defined $queue;
301    $self->LimitToLookupType( 'RT::Queue-RT::Ticket' );
302 }
303
304
305 =head2 LimitToGlobal
306
307 Limits the Custom Field collection to global ticket CFs; this limit is
308 OR'd with L</LimitToQueue> limits.
309
310 Note that this will cause the collection to only return ticket CFs.
311
312 =cut
313
314 sub LimitToGlobal  {
315    my $self = shift;
316
317   $self->Limit (ALIAS => $self->_OCFAlias,
318                 ENTRYAGGREGATOR => 'OR',
319                 FIELD => 'ObjectId',
320                 VALUE => 0);
321   $self->LimitToLookupType( 'RT::Queue-RT::Ticket' );
322 }
323
324
325 =head2 ApplySortOrder
326
327 Sort custom fields according to thier order application to objects. It's
328 expected that collection contains only records of one
329 L<RT::CustomField/LookupType> and applied to one object or globally
330 (L</LimitToGlobalOrObjectId>), otherwise sorting makes no sense.
331
332 =cut
333
334 sub ApplySortOrder {
335     my $self = shift;
336     my $order = shift || 'ASC';
337     $self->OrderByCols( {
338         ALIAS => $self->_OCFAlias,
339         FIELD => 'SortOrder',
340         ORDER => $order,
341     } );
342 }
343
344
345 =head2 ContextObject
346
347 Returns context object for this collection of custom fields,
348 but only if it's defined.
349
350 =cut
351
352 sub ContextObject {
353     my $self = shift;
354     return $self->{'context_object'};
355 }
356
357
358 =head2 SetContextObject
359
360 Sets context object for this collection of custom fields.
361
362 =cut
363
364 sub SetContextObject {
365     my $self = shift;
366     return $self->{'context_object'} = shift;
367 }
368
369
370 sub _OCFAlias {
371     my $self = shift;
372     return RT::ObjectCustomFields->new( $self->CurrentUser )
373         ->JoinTargetToThis( $self => @_ );
374 }
375
376
377 =head2 Next
378
379 Returns the next custom field that this user can see.
380
381 =cut
382
383 sub Next {
384     my $self = shift;
385
386     my $CF = $self->SUPER::Next();
387     return $CF unless $CF;
388
389     $CF->SetContextObject( $self->ContextObject );
390
391     return $self->Next unless $CF->CurrentUserHasRight('SeeCustomField');
392     return $CF;
393 }
394
395 =head2 NewItem
396
397 Returns an empty new RT::CustomField item
398 Overrides <RT::SearchBuilder/NewItem> to make sure </ContextObject>
399 is inherited.
400
401 =cut
402
403 sub NewItem {
404     my $self = shift;
405     my $res = RT::CustomField->new($self->CurrentUser);
406     $res->SetContextObject($self->ContextObject);
407     return $res;
408 }
409
410 RT::Base->_ImportOverlays();
411
412 1;