import of rt 3.0.9
[freeside.git] / rt / lib / RT / CustomField_Overlay.pm
1 # BEGIN LICENSE BLOCK
2
3 # Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
4
5 # (Except where explictly superceded by other copyright notices)
6
7 # This work is made available to you under the terms of Version 2 of
8 # the GNU General Public License. A copy of that license should have
9 # been provided with this software, but in any event can be snarfed
10 # from www.gnu.org.
11
12 # This work is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 # General Public License for more details.
16
17 # Unless otherwise specified, all modifications, corrections or
18 # extensions to this work which alter its source code become the
19 # property of Best Practical Solutions, LLC when submitted for
20 # inclusion in the work.
21
22
23 # END LICENSE BLOCK
24 use strict;
25 no warnings qw(redefine);
26
27 use vars qw(@TYPES %TYPES);
28
29 use RT::CustomFieldValues;
30 use RT::TicketCustomFieldValues;
31
32 # Enumerate all valid types for this custom field
33 @TYPES = (
34     'SelectSingle',     # loc
35     'SelectMultiple',   # loc
36     'FreeformSingle',   # loc
37     'FreeformMultiple', # loc
38 );
39
40 # Populate a hash of types of easier validation
41 for (@TYPES) { $TYPES{$_} = 1};
42
43
44
45
46 =head1 NAME
47
48   RT::CustomField_Overlay 
49
50 =head1 DESCRIPTION
51
52 =head1 'CORE' METHODS
53
54 =cut
55
56
57
58 =head2 Create PARAMHASH
59
60 Create takes a hash of values and creates a row in the database:
61
62   varchar(200) 'Name'.
63   varchar(200) 'Type'.
64   int(11) 'Queue'.
65   varchar(255) 'Description'.
66   int(11) 'SortOrder'.
67   smallint(6) 'Disabled'.
68
69 =cut
70
71
72
73
74 sub Create {
75     my $self = shift;
76     my %args = ( 
77                 Name => '',
78                 Type => '',
79                 Queue => '0',
80                 Description => '',
81                 SortOrder => '0',
82                 Disabled => '0',
83
84                   @_);
85
86     
87
88     if (  ! $args{'Queue'} ) {
89         unless ( $self->CurrentUser->HasRight( Object => $RT::System, Right => 'AdminCustomFields') ) {
90             return ( 0, $self->loc('Permission Denied') );
91         }
92     }
93     else {
94         my $queue = RT::Queue->new($self->CurrentUser);
95         $queue->Load($args{'Queue'});
96         unless ($queue->Id) {
97             return (0, $self->loc("Queue not found"));
98         }
99         unless ( $queue->CurrentUserHasRight('AdminCustomFields') ) {
100             return ( 0, $self->loc('Permission Denied') );
101         }
102     }
103     $self->SUPER::Create(
104                          Name => $args{'Name'},
105                          Type => $args{'Type'},
106                          Queue => $args{'Queue'},
107                          Description => $args{'Description'},
108                          SortOrder => $args{'SortOrder'},
109                          Disabled => $args{'Disabled'},
110 );
111
112 }
113
114
115 # {{{ sub LoadByNameAndQueue
116
117 =head2  LoadByNameAndQueue (Queue => QUEUEID, Name => NAME)
118
119 Loads the Custom field named NAME for Queue QUEUE. If QUEUE is 0,
120 loads a global custom field
121
122 =cut
123
124 # Compatibility for API change after 3.0 beta 1
125 *LoadNameAndQueue = \&LoadByNameAndQueue;
126
127 sub LoadByNameAndQueue {
128     my $self = shift;
129     my %args = (
130         Queue => undef,
131         Name  => undef,
132         @_,
133     );
134
135     if ($args{'Queue'} =~ /\D/) {
136         my $QueueObj = RT::Queue->new($self->CurrentUser);
137         $QueueObj->Load($args{'Queue'});
138         $args{'Queue'} = $QueueObj->Id;
139     }
140
141     return ( $self->LoadByCols( Name => $args{'Name'}, Queue => $args{'Queue'} ) );
142
143 }
144
145 # }}}
146
147 # {{{ Dealing with custom field values 
148
149 =begin testing
150 use_ok(RT::CustomField);
151 ok(my $cf = RT::CustomField->new($RT::SystemUser));
152 ok(my ($id, $msg)=  $cf->Create( Name => 'TestingCF',
153                                  Queue => '0',
154                                  SortOrder => '1',
155                                  Description => 'A Testing custom field',
156                                  Type=> 'SelectSingle'), 'Created a global CustomField');
157 ok($id != 0, 'Global custom field correctly created');
158 ok ($cf->SingleValue);
159 ok($cf->Type eq 'SelectSingle');
160
161 ok($cf->SetType('SelectMultiple'));
162 ok($cf->Type eq 'SelectMultiple');
163 ok(!$cf->SingleValue );
164 ok(my ($bogus_val, $bogus_msg) = $cf->SetType('BogusType') , "Trying to set a custom field's type to a bogus type");
165 ok($bogus_val == 0, "Unable to set a custom field's type to a bogus type");
166
167 ok(my $bad_cf = RT::CustomField->new($RT::SystemUser));
168 ok(my ($bad_id, $bad_msg)=  $cf->Create( Name => 'TestingCF-bad',
169                                  Queue => '0',
170                                  SortOrder => '1',
171                                  Description => 'A Testing custom field with a bogus Type',
172                                  Type=> 'SelectSingleton'), 'Created a global CustomField with a bogus type');
173 ok($bad_id == 0, 'Global custom field correctly decided to not create a cf with a bogus type ');
174
175 =end testing
176
177 =cut
178
179 # {{{ AddValue
180
181 =head2 AddValue HASH
182
183 Create a new value for this CustomField.  Takes a paramhash containing the elements Name, Description and SortOrder
184
185 =begin testing
186
187 ok(my $cf = RT::CustomField->new($RT::SystemUser));
188 $cf->Load(1);
189 ok($cf->Id == 1);
190 ok(my ($val,$msg)  = $cf->AddValue(Name => 'foo' , Description => 'TestCFValue', SortOrder => '6'));
191 ok($val != 0);
192 ok (my ($delval, $delmsg) = $cf->DeleteValue($val));
193 ok ($delval != 0);
194
195 =end testing
196
197 =cut
198
199 sub AddValue {
200         my $self = shift;
201         my %args = ( Name => undef,
202                      Description => undef,
203                      SortOrder => undef,
204                      @_ );
205
206     unless ($self->CurrentUserHasRight('AdminCustomFields')) {
207         return (0, $self->loc('Permission Denied'));
208     }
209
210     unless ($args{'Name'}) {
211         return(0, $self->loc("Can't add a custom field value without a name"));
212     }
213         my $newval = RT::CustomFieldValue->new($self->CurrentUser);
214         return($newval->Create(
215                      CustomField => $self->Id,
216              Name =>$args{'Name'},
217              Description => ($args{'Description'} || ''),
218              SortOrder => ($args{'SortOrder'} || '0')
219         ));    
220 }
221
222
223 # }}}
224
225 # {{{ DeleteValue
226
227 =head2 DeleteValue ID
228
229 Deletes a value from this custom field by id. 
230
231 Does not remove this value for any article which has had it selected    
232
233 =cut
234
235 sub DeleteValue {
236         my $self = shift;
237     my $id = shift;
238     unless ($self->CurrentUserHasRight('AdminCustomFields')) {
239         return (0, $self->loc('Permission Denied'));
240     }
241
242         my $val_to_del = RT::CustomFieldValue->new($self->CurrentUser);
243         $val_to_del->Load($id);
244         unless ($val_to_del->Id) {
245                 return (0, $self->loc("Couldn't find that value"));
246         }
247         unless ($val_to_del->CustomField == $self->Id) {
248                 return (0, $self->loc("That is not a value for this custom field"));
249         }
250
251         my $retval = $val_to_del->Delete();
252     if ($retval) {
253         return ($retval, $self->loc("Custom field value deleted"));
254     } else {
255         return(0, $self->loc("Custom field value could not be deleted"));
256     }
257 }
258
259 # }}}
260
261 # {{{ Values
262
263 =head2 Values FIELD
264
265 Return a CustomFieldeValues object of all acceptable values for this Custom Field.
266
267
268 =cut
269
270 sub Values {
271     my $self = shift;
272
273     my $cf_values = RT::CustomFieldValues->new($self->CurrentUser);
274     if ( $self->__Value('Queue') == 0 || $self->CurrentUserHasRight( 'SeeQueue') ) {
275         $cf_values->LimitToCustomField($self->Id);
276     }
277     return ($cf_values);
278 }
279
280 # }}}
281
282 # }}}
283
284 # {{{ Ticket related routines
285
286 # {{{ ValuesForTicket
287
288 =head2 ValuesForTicket TICKET
289
290 Returns a RT::TicketCustomFieldValues object of this Field's values for TICKET.
291 TICKET is a ticket id.
292
293
294 =cut
295
296 sub ValuesForTicket {
297         my $self = shift;
298     my $ticket_id = shift;
299
300         my $values = new RT::TicketCustomFieldValues($self->CurrentUser);
301         $values->LimitToCustomField($self->Id);
302     $values->LimitToTicket($ticket_id);
303
304         return ($values);
305 }
306
307 # }}}
308
309 # {{{ AddValueForTicket
310
311 =head2 AddValueForTicket HASH
312
313 Adds a custom field value for a ticket. Takes a param hash of Ticket and Content
314
315 =cut
316
317 sub AddValueForTicket {
318         my $self = shift;
319         my %args = ( Ticket => undef,
320                  Content => undef,
321                      @_ );
322
323         my $newval = RT::TicketCustomFieldValue->new($self->CurrentUser);
324         my $val = $newval->Create(Ticket => $args{'Ticket'},
325                             Content => $args{'Content'},
326                             CustomField => $self->Id);
327
328     return($val);
329
330 }
331
332
333 # }}}
334
335 # {{{ DeleteValueForTicket
336
337 =head2 DeleteValueForTicket HASH
338
339 Adds a custom field value for a ticket. Takes a param hash of Ticket and Content
340
341 =cut
342
343 sub DeleteValueForTicket {
344         my $self = shift;
345         my %args = ( Ticket => undef,
346                  Content => undef,
347                      @_ );
348
349         my $oldval = RT::TicketCustomFieldValue->new($self->CurrentUser);
350     $oldval->LoadByTicketContentAndCustomField (Ticket => $args{'Ticket'}, 
351                                                 Content =>  $args{'Content'}, 
352                                                 CustomField => $self->Id );
353     # check ot make sure we found it
354     unless ($oldval->Id) {
355         return(0, $self->loc("Custom field value [_1] could not be found for custom field [_2]", $args{'Content'}, $self->Name));
356     }
357     # delete it
358
359     my $ret = $oldval->Delete();
360     unless ($ret) {
361         return(0, $self->loc("Custom field value could not be found"));
362     }
363     return(1, $self->loc("Custom field value deleted"));
364 }
365
366
367 # }}}
368 # }}}
369
370
371 =head2 ValidateQueue Queue
372
373 Make sure that the queue specified is a valid queue name
374
375 =cut
376
377 sub ValidateQueue {
378     my $self = shift;
379     my $id = shift;
380
381     if ($id eq '0') { # 0 means "Global" null would _not_ be ok.
382         return (1); 
383     }
384
385     my $q = RT::Queue->new($RT::SystemUser);
386     $q->Load($id);
387     unless ($q->id) {
388         return undef;
389     }
390     return (1);
391
392
393 }
394
395
396 # {{{ Types
397
398 =head2 Types 
399
400 Retuns an array of the types of CustomField that are supported
401
402 =cut
403
404 sub Types {
405         return (@TYPES);
406 }
407
408 # }}}
409
410
411 =head2 FriendlyType [TYPE]
412
413 Returns a localized human-readable version of the custom field type.
414 If a custom field type is specified as the parameter, the friendly type for that type will be returned
415
416 =cut
417
418 sub FriendlyType {
419     my $self = shift;
420
421     my $type = shift || $self->Type;
422
423     if ( $type eq 'SelectSingle' ) {
424         return ( $self->loc('Select one value') );
425     }
426     elsif ( $type eq 'SelectMultiple' ) {
427         return ( $self->loc('Select multiple values') );
428     }
429     elsif ( $type eq 'FreeformSingle' ) {
430         return ( $self->loc('Enter one value') );
431     }
432     elsif ( $type eq 'FreeformMultiple' ) {
433         return ( $self->loc('Enter multiple values') );
434     }
435     else {
436         return ( $self->loc( $self->Type ) );
437     }
438 }
439
440
441 =head2 ValidateType TYPE
442
443 Takes a single string. returns true if that string is a value
444 type of custom field
445
446 =begin testing
447
448 ok(my $cf = RT::CustomField->new($RT::SystemUser));
449 ok($cf->ValidateType('SelectSingle'));
450 ok($cf->ValidateType('SelectMultiple'));
451 ok(!$cf->ValidateType('SelectFooMultiple'));
452
453 =end testing
454
455 =cut
456
457 sub ValidateType {
458     my $self = shift;
459     my $type = shift;
460
461     if( $TYPES{$type}) {
462         return(1);
463     }
464     else {
465         return undef;
466     }
467 }
468
469 # {{{ SingleValue
470
471 =head2 SingleValue
472
473 Returns true if this CustomField only accepts a single value. 
474 Returns false if it accepts multiple values
475
476 =cut
477
478 sub SingleValue {
479     my $self = shift;
480     if ($self->Type =~  /Single$/) {
481         return 1;
482     } 
483     else {
484         return undef;
485     }
486 }
487
488 # }}}
489
490 # {{{ sub CurrentUserHasRight
491
492 =head2 CurrentUserHasRight RIGHT
493
494 Helper function to call the custom field's queue's CurrentUserHasRight with the passed in args.
495
496 =cut
497
498 sub CurrentUserHasRight {
499     my $self = shift;
500     my $right = shift;
501     # if there's no queue, we want to know about a global right
502     if ( ( !defined $self->__Value('Queue') ) || ( $self->__Value('Queue') == 0 ) ) {
503          return $self->CurrentUser->HasRight( Object => $RT::System, Right => $right); 
504     } else {
505         return ( $self->QueueObj->CurrentUserHasRight($right) );
506     }
507 }
508
509 # }}}
510
511 # {{{ sub _Set
512
513 sub _Set {
514     my $self = shift;
515
516     unless ( $self->CurrentUserHasRight('AdminCustomFields') ) {
517         return ( 0, $self->loc('Permission Denied') );
518     }
519     return ( $self->SUPER::_Set(@_) );
520
521 }
522
523 # }}}
524
525 # {{{ sub _Value 
526
527 =head2 _Value
528
529 Takes the name of a table column.
530 Returns its value as a string, if the user passes an ACL check
531
532 =cut
533
534 sub _Value {
535
536     my $self  = shift;
537     my $field = shift;
538
539     # We need to expose the queue so that we can do things like ACL checks
540     if ( $field eq 'Queue') {
541           return ( $self->SUPER::_Value($field) );
542      }
543
544
545     #Anybody can see global custom fields, otherwise we need to do the rights check
546         unless ( $self->__Value('Queue') == 0 || $self->CurrentUserHasRight( 'SeeQueue') ) {
547             return (undef);
548         }
549     return ( $self->__Value($field) );
550
551 }
552
553 # }}}
554 # {{{ sub SetDisabled
555
556 =head2 SetDisabled
557
558 Takes a boolean.
559 1 will cause this custom field to no longer be avaialble for tickets.
560 0 will re-enable this queue
561
562 =cut
563
564 # }}}
565
566 1;