import rt 2.0.14
[freeside.git] / rt / lib / RT / KeywordSelect.pm
1 #$Header: /home/cvs/cvsroot/freeside/rt/lib/RT/Attic/KeywordSelect.pm,v 1.1 2002-08-12 06:17:07 ivan Exp $
2
3 package RT::KeywordSelect;
4
5 use strict;
6 use vars qw(@ISA);
7 use RT::Record;
8 use RT::Keyword;
9
10 @ISA = qw(RT::Record);
11
12 # {{{ POD
13
14 =head1 NAME
15
16  RT::KeywordSelect - Manipulate an RT::KeywordSelect record
17
18 =head1 SYNOPSIS
19
20   use RT::KeywordSelect;
21
22   my $keyword_select = RT::KeywordSelect->new($CurrentUser);
23   $keyword_select->Create(
24     Keyword     => 20,
25     ObjectType => 'Ticket',
26     Name       => 'Choices'
27   );
28
29   my $keyword_select = RT::KeywordSelect->new($CurrentUser);
30   $keyword_select->Create(
31     Name        => 'Choices',                     
32     Keyword     => 20,
33     ObjectType  => 'Ticket',
34     ObjectField => 'Queue',
35     ObjectValue => 1,
36     Single      => 1,
37     Depth => 4,
38   );
39
40 =head1 DESCRIPTION
41
42 An B<RT::KeywordSelect> object is a link between a Keyword and a object
43 type (one of: Ticket), titled by the I<Name> field of the B<RT::Keyword> such
44 that:
45
46 =over 4
47
48 =item Object display will contain a field, titled with the I<Name> field and
49   showing any descendent keywords which are related to this object via the
50   B<RT::ObjectKeywords> table.
51
52 =item Object creation for this object will contain a field titled with the
53   I<Name> field and containing the descendents of the B<RT::Keyword> as
54   choices.  If the I<Single> field of this B<RT::KeywordSelect> is true, each
55   object must be associated (via an B<RT::ObjectKeywords> record) to a single
56   descendent.  If the I<Single> field is false, each object may be connect to
57   zero, one, or many descendents.
58
59 =item Searches for this object type will contain a selection field titled with
60   the I<Name> field and containing the descendents of the B<RT::Keyword> as
61   choices.
62
63 =item If I<ObjectField> is defined (one of: Queue), all of the above apply only
64   when the value of I<ObjectField> (Queue) in B<ObjectType> (Ticket) matches
65   I<ObjectValue>.
66
67 =back
68
69
70 =begin testing
71
72 ok (require RT::TestHarness);
73 ok (require RT::KeywordSelects);
74
75 =end testing
76
77
78 =head1 METHODS
79
80
81 =cut
82
83
84 =over 4
85
86 =item new CURRENT_USER
87
88 Takes a single argument, an RT::CurrentUser object.  Instantiates a new
89 (uncreated) RT::KeywordSelect object.
90
91 =cut
92 # }}}
93
94 # {{{ sub _Init
95 sub _Init {
96     my $self = shift;
97     $self->{'table'} = "KeywordSelects";
98     $self->SUPER::_Init(@_);
99 }
100 # }}}
101
102 # {{{ sub _Accessible
103 sub _Accessible {
104     my $self = shift;
105     my %Cols = (
106                 Name => 'read/write',
107                 Keyword => 'read/write', # link to Keywords.  Can be specified by id
108                 Single => 'read/write', # bool (described below)
109
110                 Depth => 'read/write', #- If non-zero, limits the descendents to this number of levels deep.
111                 ObjectType  => 'read/write', # currently only C<Ticket>
112                 ObjectField => 'read/write', #optional, currently only C<Queue>
113                 ObjectValue => 'read/write', #constrains KeywordSelect function to when B<ObjectType>.I<ObjectField> equals I<ObjectValue>
114                 Disabled => 'read/write'
115                );
116     return($self->SUPER::_Accessible(@_, %Cols));  
117 }
118 # }}}
119
120 # {{{ sub LoadByName
121
122 =head2 LoadByName( Name => [NAME], Queue => [QUEUE_ID])
123 .  Takes a queue id and a keyword select name. 
124     tries to load the keyword select for that queue. if that fails, it tries to load it
125     without a queue specified.
126
127 =cut
128
129
130 sub LoadByName {
131     my $self = shift;
132     my %args = ( Name => undef,
133                  Queue => undef,
134                  @_
135                );
136     if ($args{'Queue'}) {
137         #Try to get the keyword select for this queue
138         $self->LoadByCols( Name => $args{'Name'}, 
139                            ObjectType => 'Ticket', 
140                            ObjectField => 'Queue', 
141                            ObjectValue => $args{'Queue'});
142     }   
143     unless ($self->Id) { #if that failed to load an object
144         #Try to get the keyword select of that name that's global
145         $self->LoadByCols( Name => $args{'Name'}, 
146                            ObjectType => 'Ticket', 
147                            ObjectField => 'Queue', 
148                            ObjectValue => '0');
149     }
150     
151     return($self->Id);
152     
153 }
154
155 # }}}
156
157 # {{{ sub Create
158 =item Create KEY => VALUE, ...
159
160 Takes a list of key/value pairs and creates a the object.  Returns the id of
161 the newly created record, or false if there was an error.
162
163 Keys are:
164
165 Keyword - link to Keywords.  Can be specified by id.
166 Name - A name for this KeywordSelect
167 Single - bool (described above)
168 Depth - If non-zero, limits the descendents to this number of levels deep.
169 ObjectType - currently only C<Ticket>
170 ObjectField - optional, currently only C<Queue>
171 ObjectValue - constrains KeywordSelect function to when B<ObjectType>.I<ObjectField> equals I<ObjectValue>
172
173 =cut
174
175 sub Create {
176     my $self = shift;
177     my %args = ( Keyword => undef,
178                  Single => 1,
179                  Depth => 0,
180                  Name => undef,
181                  ObjectType => undef,
182                  ObjectField => undef,
183                  ObjectValue => undef,
184                  @_);
185
186     #If we're talking about a keyword select based on a ticket's 'Queue' field
187     if  ( ($args{'ObjectField'} eq 'Queue') and
188           ($args{'ObjectType'} eq 'Ticket')) {
189         
190         #If we're talking about a keywordselect for all queues
191         if ($args{'ObjectValue'} == 0) {
192             unless( $self->CurrentUserHasSystemRight('AdminKeywordSelects')) {
193                 return (0, 'Permission Denied');
194             }
195         }  
196         #otherwise, we're talking about a keywordselect for a specific queue
197         else {
198             unless ($self->CurrentUserHasQueueRight( Right => 'AdminKeywordSelects',
199                                                      Queue => $args{'ObjectValue'})) {
200                 return (0, 'Permission Denied');
201             }
202         }
203     }
204     else {
205         return (0, "Can't create a KeywordSelect for that object/field combo");
206     }
207
208     my $Keyword = new RT::Keyword($self->CurrentUser);
209
210     if ( $args{'Keyword'} && $args{'Keyword'} !~ /^\d+$/ ) {
211         $Keyword->LoadByPath($args{'Keyword'});
212     }   
213     else {
214         $Keyword->Load($args{'Keyword'});
215     }
216
217     unless ($Keyword->Id) {
218         $RT::Logger->debug("Keyword ".$args{'Keyword'} ." not found\n");
219         return(0, 'Keyword not found');
220     }
221     
222     $args{'Name'} = $Keyword->Name if  (!$args{'Name'});
223     
224     my $val = $self->SUPER::Create( Name => $args{'Name'},
225                                     Keyword => $Keyword->Id,
226                                     Single => $args{'Single'},
227                                     Depth => $args{'Depth'},
228                                     ObjectType => $args{'ObjectType'},
229                                     ObjectField => $args{'ObjectField'},
230                                     ObjectValue => $args{'ObjectValue'});
231     if ($val) {
232         return ($val, 'KeywordSelect Created');
233     }
234     else {
235         return (0, 'System error. KeywordSelect not created');
236         
237     }
238 }
239 # }}}
240
241 # {{{ sub Delete
242
243 sub Delete {
244     my $self = shift;
245     
246     return (0, 'Deleting this object would break referential integrity.');
247 }
248
249 # }}}
250
251
252 # {{{ sub SetDisabled
253
254 =head2 Sub SetDisabled
255
256 Toggles the KeywordSelect's disabled flag.
257
258
259 =cut 
260
261 sub SetDisabled {
262     my $self = shift;
263     my $value = shift;
264
265     unless ($self->CurrentUserHasRight('AdminKeywordSelects')) {
266         return (0, "Permission Denied");
267     }
268     return($self->_Set(Field => 'Disabled', Value => $value));
269 }
270
271 # }}}
272
273 # {{{ sub KeywordObj
274
275 =item KeywordObj
276
277 Returns the B<RT::Keyword> referenced by the I<Keyword> field.
278
279 =cut
280
281 sub KeywordObj {
282     my $self = shift;
283
284     my $Keyword = new RT::Keyword($self->CurrentUser);
285     $Keyword->Load( $self->Keyword ); #or ?
286     return($Keyword);
287
288 # }}}
289
290 # {{{ sub Object
291
292 =item Object
293
294 Returns the object (currently only RT::Queue) specified by ObjectField and ObjectValue.
295
296 =cut
297
298 sub Object {
299     my $self = shift;
300     if ( $self->ObjectField eq 'Queue' ) {
301         my $Queue = new RT::Queue($self->CurrentUser);
302         $Queue->Load( $self->ObjectValue );
303         return ($Queue);
304     } else {
305         $RT::Logger->error("$self trying to load an object value for a non-queue object");
306         return (undef);
307     }
308 }
309
310 # }}}
311
312 # {{{ sub _Set
313
314 # does an acl check, then passes off the call
315 sub _Set {
316     my $self = shift;
317
318     unless ($self->CurrentUserHasRight('AdminKeywordSelects')) {
319         return (0, "Permission Denied");
320     }
321     
322     return ($self->SUPER::_Set(@_));
323
324 }
325
326 # }}}
327
328
329 # {{{ sub CurrentUserHasQueueRight 
330
331 =head2 CurrentUserHasQueueRight ( Queue => QUEUEID, Right => RIGHTNANAME )
332
333 Check to see whether the current user has the specified right for the specified queue.
334
335 =cut
336
337 sub CurrentUserHasQueueRight {
338     my $self = shift;
339     my %args = (Queue => undef,
340                 Right => undef,
341                 @_
342                 );
343     return ($self->HasRight( Right => $args{'Right'},
344                              Principal => $self->CurrentUser->UserObj,
345                              Queue => $args{'Queue'}));
346 }
347
348 # }}}
349
350 # {{{ sub CurrentUserHasSystemRight 
351
352 =head2 CurrentUserHasSystemRight RIGHTNAME
353
354 Check to see whether the current user has the specified right for the 'system' scope.
355
356 =cut
357
358 sub CurrentUserHasSystemRight {
359     my $self = shift;
360     my $right = shift;
361     $RT::Logger->debug("$self in hashsysright for right $right\n");
362     return ($self->HasRight( Right => $right,
363                              System => 1,
364                              Principal => $self->CurrentUser->UserObj));
365 }
366
367 # }}}
368
369 # {{{ sub CurrentUserHasRight
370
371 =item CurrentUserHasRight RIGHT  [QUEUEID]
372
373 Takes a rightname as a string. Can take a queue id as a second
374 optional parameter, which can be useful to a routine like create.
375 Helper menthod for HasRight. Presets Principal to CurrentUser then 
376 calls HasRight.
377
378 =cut
379
380 sub CurrentUserHasRight {
381     my $self = shift;
382     my $right = shift;
383     return ($self->HasRight( Principal => $self->CurrentUser->UserObj,
384                              Right => $right,
385                            ));
386 }
387
388 # }}}
389
390 # {{{ sub HasRight
391
392 =item HasRight
393
394 Takes a param-hash consisting of "Right" and "Principal"  Principal is 
395 an RT::User object or an RT::CurrentUser object. "Right" is a textual
396 Right string that applies to KeywordSelects
397
398 =cut
399
400 sub HasRight {
401     my $self = shift;
402     my %args = ( Right => undef,
403                  Principal => undef,
404                  Queue => undef,
405                  System => undef,
406                  @_ );
407
408     #If we're explicitly specifying a queue, as we need to do on create
409     if ($args{'Queue'}) {
410         return ($args{'Principal'}->HasQueueRight(Right => $args{'Right'},
411                                                   Queue => $args{'Queue'}));
412     }
413     #else if we're specifying to check a system right
414     elsif ($args{'System'}) {
415         return( $args{'Principal'}->HasSystemRight( $args{'Right'} ));
416     }   
417
418     #else if we 're using the object's queue
419     elsif (($self->__Value('ObjectField') eq 'Queue') and
420            ($self->__Value('ObjectValue') > 0 )) {
421         return ($args{'Principal'}->HasQueueRight(Right => $args{'Right'},
422                                                   Queue => $self->__Value('ObjectValue') )); 
423     }
424     
425     #If the object is system scoped.
426     else {
427         return( $args{'Principal'}->HasSystemRight( $args{'Right'} ));
428     }
429 }
430
431 # }}}
432
433 =back
434
435 =head1 AUTHORS
436
437 Ivan Kohler <ivan-rt@420.am>, Jesse Vincent <jesse@fsck.com>
438
439 =head1 BUGS
440
441 The ACL system for this object is more byzantine than it should be.  reworking it eventually
442 would be a good thing.
443
444 =head1 SEE ALSO
445
446 L<RT::KeywordSelects>, L<RT::Keyword>, L<RT::Keywords>, L<RT::ObjectKeyword>,
447 L<RT::ObjectKeywords>, L<RT::Record>
448
449 =cut
450
451 1;
452