import of rt 3.0.9
[freeside.git] / rt / lib / RT / Queue_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 =head1 NAME
25
26   RT::Queue - an RT Queue object
27
28 =head1 SYNOPSIS
29
30   use RT::Queue;
31
32 =head1 DESCRIPTION
33
34
35 =head1 METHODS
36
37 =begin testing 
38
39 use RT::Queue;
40
41 =end testing
42
43 =cut
44
45 use strict;
46 no warnings qw(redefine);
47
48 use vars qw(@STATUS @ACTIVE_STATUS @INACTIVE_STATUS $RIGHTS);
49 use RT::Groups;
50 use RT::ACL;
51
52
53 @ACTIVE_STATUS = qw(new open stalled);
54 @INACTIVE_STATUS = qw(resolved rejected deleted);
55 @STATUS = (@ACTIVE_STATUS, @INACTIVE_STATUS);
56
57 # $self->loc('new'); # For the string extractor to get a string to localize
58 # $self->loc('open'); # For the string extractor to get a string to localize
59 # $self->loc('stalled'); # For the string extractor to get a string to localize
60 # $self->loc('resolved'); # For the string extractor to get a string to localize
61 # $self->loc('rejected'); # For the string extractor to get a string to localize
62 # $self->loc('deleted'); # For the string extractor to get a string to localize
63
64
65 $RIGHTS = {
66     SeeQueue            => 'Can this principal see this queue',       # loc_pair
67     AdminQueue          => 'Create, delete and modify queues',        # loc_pair
68     ShowACL             => 'Display Access Control List',             # loc_pair
69     ModifyACL           => 'Modify Access Control List',              # loc_pair
70     ModifyQueueWatchers => 'Modify the queue watchers',               # loc_pair
71     AdminCustomFields   => 'Create, delete and modify custom fields', # loc_pair
72     ModifyTemplate      => 'Modify Scrip templates for this queue',   # loc_pair
73     ShowTemplate        => 'Display Scrip templates for this queue',  # loc_pair
74
75     ModifyScrips => 'Modify Scrips for this queue',                   # loc_pair
76     ShowScrips   => 'Display Scrips for this queue',                  # loc_pair
77
78     ShowTicket         => 'Show ticket summaries',                    # loc_pair
79     ShowTicketComments => 'Show ticket private commentary',           # loc_pair
80
81     Watch => 'Sign up as a ticket Requestor or ticket or queue Cc',   # loc_pair
82     WatchAsAdminCc  => 'Sign up as a ticket or queue AdminCc',        # loc_pair
83     CreateTicket    => 'Create tickets in this queue',                # loc_pair
84     ReplyToTicket   => 'Reply to tickets',                            # loc_pair
85     CommentOnTicket => 'Comment on tickets',                          # loc_pair
86     OwnTicket       => 'Own tickets',                                 # loc_pair
87     ModifyTicket    => 'Modify tickets',                              # loc_pair
88     DeleteTicket    => 'Delete tickets',                              # loc_pair
89     TakeTicket      => 'Take tickets',                                # loc_pair
90     StealTicket     => 'Steal tickets',                               # loc_pair
91
92 };
93
94 # Tell RT::ACE that this sort of object can get acls granted
95 $RT::ACE::OBJECT_TYPES{'RT::Queue'} = 1;
96
97 # TODO: This should be refactored out into an RT::ACLedObject or something
98 # stuff the rights into a hash of rights that can exist.
99
100 foreach my $right ( keys %{$RIGHTS} ) {
101     $RT::ACE::LOWERCASERIGHTNAMES{ lc $right } = $right;
102 }
103     
104
105 =head2 AvailableRights
106
107 Returns a hash of available rights for this object. The keys are the right names and the values are a description of what the rights do
108
109 =cut
110
111 sub AvailableRights {
112     my $self = shift;
113     return($RIGHTS);
114 }
115
116 # {{{ ActiveStatusArray
117
118 =head2 ActiveStatusArray
119
120 Returns an array of all ActiveStatuses for this queue
121
122 =cut
123
124 sub ActiveStatusArray {
125     my $self = shift;
126     return (@ACTIVE_STATUS);
127 }
128
129 # }}}
130
131 # {{{ InactiveStatusArray
132
133 =head2 InactiveStatusArray
134
135 Returns an array of all InactiveStatuses for this queue
136
137 =cut
138
139 sub InactiveStatusArray {
140     my $self = shift;
141     return (@INACTIVE_STATUS);
142 }
143
144 # }}}
145
146 # {{{ StatusArray
147
148 =head2 StatusArray
149
150 Returns an array of all statuses for this queue
151
152 =cut
153
154 sub StatusArray {
155     my $self = shift;
156     return (@STATUS);
157 }
158
159 # }}}
160
161 # {{{ IsValidStatus
162
163 =head2 IsValidStatus VALUE
164
165 Returns true if VALUE is a valid status.  Otherwise, returns 0
166
167 =for testing
168 my $q = RT::Queue->new($RT::SystemUser);
169 ok($q->IsValidStatus('new')== 1, 'New is a valid status');
170 ok($q->IsValidStatus('f00')== 0, 'f00 is not a valid status');
171
172 =cut
173
174 sub IsValidStatus {
175     my $self  = shift;
176     my $value = shift;
177
178     my $retval = grep ( /^$value$/, $self->StatusArray );
179     return ($retval);
180
181 }
182
183 # }}}
184
185 # {{{ IsActiveStatus
186
187 =head2 IsActiveStatus VALUE
188
189 Returns true if VALUE is a Active status.  Otherwise, returns 0
190
191 =for testing
192 my $q = RT::Queue->new($RT::SystemUser);
193 ok($q->IsActiveStatus('new')== 1, 'New is a Active status');
194 ok($q->IsActiveStatus('rejected')== 0, 'Rejected is an inactive status');
195 ok($q->IsActiveStatus('f00')== 0, 'f00 is not a Active status');
196
197 =cut
198
199 sub IsActiveStatus {
200     my $self  = shift;
201     my $value = shift;
202
203     my $retval = grep ( /^$value$/, $self->ActiveStatusArray );
204     return ($retval);
205
206 }
207
208 # }}}
209
210 # {{{ IsInactiveStatus
211
212 =head2 IsInactiveStatus VALUE
213
214 Returns true if VALUE is a Inactive status.  Otherwise, returns 0
215
216 =for testing
217 my $q = RT::Queue->new($RT::SystemUser);
218 ok($q->IsInactiveStatus('new')== 0, 'New is a Active status');
219 ok($q->IsInactiveStatus('rejected')== 1, 'rejeected is an Inactive status');
220 ok($q->IsInactiveStatus('f00')== 0, 'f00 is not a Active status');
221
222 =cut
223
224 sub IsInactiveStatus {
225     my $self  = shift;
226     my $value = shift;
227
228     my $retval = grep ( /^$value$/, $self->InactiveStatusArray );
229     return ($retval);
230
231 }
232
233 # }}}
234
235
236 # {{{ sub Create
237
238 =head2 Create
239
240 Create takes the name of the new queue 
241 If you pass the ACL check, it creates the queue and returns its queue id.
242
243 =cut
244
245 sub Create {
246     my $self = shift;
247     my %args = (
248         Name              => undef,
249         CorrespondAddress => '',
250         Description       => '',
251         CommentAddress    => '',
252         InitialPriority   => "0",
253         FinalPriority     => "0",
254         DefaultDueIn      => "0",
255         @_
256     );
257
258     unless ( $self->CurrentUser->HasRight(Right => 'AdminQueue', Object => $RT::System) )
259     {    #Check them ACLs
260         return ( 0, $self->loc("No permission to create queues") );
261     }
262
263     unless ( $self->ValidateName( $args{'Name'} ) ) {
264         return ( 0, $self->loc('Queue already exists') );
265     }
266
267     #TODO better input validation
268     $RT::Handle->BeginTransaction();
269
270     my $id = $self->SUPER::Create(%args);
271     unless ($id) {
272         $RT::Handle->Rollback();
273         return ( 0, $self->loc('Queue could not be created') );
274     }
275
276     my $create_ret = $self->_CreateQueueGroups();
277     unless ($create_ret) {
278         $RT::Handle->Rollback();
279         return ( 0, $self->loc('Queue could not be created') );
280     }
281
282     $RT::Handle->Commit();
283     return ( $id, $self->loc("Queue created") );
284 }
285
286 # }}}
287
288 # {{{ sub Delete 
289
290 sub Delete {
291     my $self = shift;
292     return ( 0,
293         $self->loc('Deleting this object would break referential integrity') );
294 }
295
296 # }}}
297
298 # {{{ sub SetDisabled
299
300 =head2 SetDisabled
301
302 Takes a boolean.
303 1 will cause this queue to no longer be avaialble for tickets.
304 0 will re-enable this queue
305
306 =cut
307
308 # }}}
309
310 # {{{ sub Load 
311
312 =head2 Load
313
314 Takes either a numerical id or a textual Name and loads the specified queue.
315
316 =cut
317
318 sub Load {
319     my $self = shift;
320
321     my $identifier = shift;
322     if ( !$identifier ) {
323         return (undef);
324     }
325
326     if ( $identifier =~ /^(\d+)$/ ) {
327         $self->SUPER::LoadById($identifier);
328     }
329     else {
330         $self->LoadByCols( Name => $identifier );
331     }
332
333     return ( $self->Id );
334
335 }
336
337 # }}}
338
339 # {{{ sub ValidateName
340
341 =head2 ValidateName NAME
342
343 Takes a queue name. Returns true if it's an ok name for
344 a new queue. Returns undef if there's already a queue by that name.
345
346 =cut
347
348 sub ValidateName {
349     my $self = shift;
350     my $name = shift;
351
352     my $tempqueue = new RT::Queue($RT::SystemUser);
353     $tempqueue->Load($name);
354
355     #If we couldn't load it :)
356     unless ( $tempqueue->id() ) {
357         return (1);
358     }
359
360     #If this queue exists, return undef
361     #Avoid the ACL check.
362     if ( $tempqueue->Name() ) {
363         return (undef);
364     }
365
366     #If the queue doesn't exist, return 1
367     else {
368         return (1);
369     }
370
371 }
372
373 # }}}
374
375 # {{{ sub Templates
376
377 =head2 Templates
378
379 Returns an RT::Templates object of all of this queue's templates.
380
381 =cut
382
383 sub Templates {
384     my $self = shift;
385
386     my $templates = RT::Templates->new( $self->CurrentUser );
387
388     if ( $self->CurrentUserHasRight('ShowTemplate') ) {
389         $templates->LimitToQueue( $self->id );
390     }
391
392     return ($templates);
393 }
394
395 # }}}
396
397 # {{{ Dealing with custom fields
398
399 # {{{  CustomField
400
401 =item CustomField NAME
402
403 Load the queue-specific custom field named NAME
404
405 =cut
406
407 sub CustomField {
408     my $self = shift;
409     my $name = shift;
410     my $cf = RT::CustomField->new($self->CurrentUser);
411     $cf->LoadByNameAndQueue(Name => $name, Queue => $self->Id); 
412     return ($cf);
413 }
414
415
416 # {{{ CustomFields
417
418 =item CustomFields
419
420 Returns an RT::CustomFields object containing all global custom fields, as well as those tied to this queue
421
422 =cut
423
424 sub CustomFields {
425     my $self = shift;
426
427     my $cfs = RT::CustomFields->new( $self->CurrentUser );
428     if ( $self->CurrentUserHasRight('SeeQueue') ) {
429         $cfs->LimitToGlobalOrQueue( $self->Id );
430     }
431     return ($cfs);
432 }
433
434 # }}}
435
436 # }}}
437
438
439 # {{{ Routines dealing with watchers.
440
441 # {{{ _CreateQueueGroups 
442
443 =head2 _CreateQueueGroups
444
445 Create the ticket groups and relationships for this ticket. 
446 This routine expects to be called from Ticket->Create _inside of a transaction_
447
448 It will create four groups for this ticket: Requestor, Cc, AdminCc and Owner.
449
450 It will return true on success and undef on failure.
451
452 =begin testing
453
454 my $Queue = RT::Queue->new($RT::SystemUser); my ($id, $msg) = $Queue->Create(Name => "Foo",
455                 );
456 ok ($id, "Foo $id was created");
457 ok(my $group = RT::Group->new($RT::SystemUser));
458 ok($group->LoadQueueRoleGroup(Queue => $id, Type=> 'Cc'));
459 ok ($group->Id, "Found the requestors object for this Queue");
460
461
462 ok ((my $add_id, $add_msg) = $Queue->AddWatcher(Type => 'Cc', Email => 'bob@fsck.com'), "Added bob at fsck.com as a requestor");
463 ok ($add_id, "Add succeeded: ($add_msg)");
464 ok(my $bob = RT::User->new($RT::SystemUser), "Creating a bob rt::user");
465 $bob->LoadByEmail('bob@fsck.com');
466 ok($bob->Id,  "Found the bob rt user");
467 ok ($Queue->IsWatcher(Type => 'Cc', PrincipalId => $bob->PrincipalId), "The Queue actually has bob at fsck.com as a requestor");;
468 ok ((my $add_id, $add_msg) = $Queue->DeleteWatcher(Type =>'Cc', Email => 'bob@fsck.com'), "Added bob at fsck.com as a requestor");
469 ok (!$Queue->IsWatcher(Type => 'Cc', Principal => $bob->PrincipalId), "The Queue no longer has bob at fsck.com as a requestor");;
470
471
472 $group = RT::Group->new($RT::SystemUser);
473 ok($group->LoadQueueRoleGroup(Queue => $id, Type=> 'Cc'));
474 ok ($group->Id, "Found the cc object for this Queue");
475 $group = RT::Group->new($RT::SystemUser);
476 ok($group->LoadQueueRoleGroup(Queue => $id, Type=> 'AdminCc'));
477 ok ($group->Id, "Found the AdminCc object for this Queue");
478
479 =end testing
480
481 =cut
482
483
484 sub _CreateQueueGroups {
485     my $self = shift;
486
487     my @types = qw(Cc AdminCc Requestor Owner);
488
489     foreach my $type (@types) {
490         my $type_obj = RT::Group->new($self->CurrentUser);
491         my ($id, $msg) = $type_obj->CreateRoleGroup(Instance => $self->Id, 
492                                                      Type => $type,
493                                                      Domain => 'RT::Queue-Role');
494         unless ($id) {
495             $RT::Logger->error("Couldn't create a Queue group of type '$type' for ticket ".
496                                $self->Id.": ".$msg);
497             return(undef);
498         }
499      }
500     return(1);
501    
502 }
503
504
505 # }}}
506
507 # {{{ sub AddWatcher
508
509 =head2 AddWatcher
510
511 AddWatcher takes a parameter hash. The keys are as follows:
512
513 Type        One of Requestor, Cc, AdminCc
514
515 PrinicpalId The RT::Principal id of the user or group that's being added as a watcher
516 Email       The email address of the new watcher. If a user with this 
517             email address can't be found, a new nonprivileged user will be created.
518
519 If the watcher you\'re trying to set has an RT account, set the Owner paremeter to their User Id. Otherwise, set the Email parameter to their Email address.
520
521 =cut
522
523 sub AddWatcher {
524     my $self = shift;
525     my %args = (
526         Type  => undef,
527         PrincipalId => undef,
528         Email => undef,
529         @_
530     );
531
532     # {{{ Check ACLS
533     #If the watcher we're trying to add is for the current user
534     if ( $self->CurrentUser->PrincipalId  eq $args{'PrincipalId'}) {
535         #  If it's an AdminCc and they don't have 
536         #   'WatchAsAdminCc' or 'ModifyTicket', bail
537         if ( $args{'Type'} eq 'AdminCc' ) {
538             unless ( $self->CurrentUserHasRight('ModifyQueueWatchers')
539                 or $self->CurrentUserHasRight('WatchAsAdminCc') ) {
540                 return ( 0, $self->loc('Permission Denied'))
541             }
542         }
543
544         #  If it's a Requestor or Cc and they don't have
545         #   'Watch' or 'ModifyTicket', bail
546         elsif ( ( $args{'Type'} eq 'Cc' ) or ( $args{'Type'} eq 'Requestor' ) ) {
547
548             unless ( $self->CurrentUserHasRight('ModifyQueueWatchers')
549                 or $self->CurrentUserHasRight('Watch') ) {
550                 return ( 0, $self->loc('Permission Denied'))
551             }
552         }
553      else {
554             $RT::Logger->warn( "$self -> AddWatcher got passed a bogus type");
555             return ( 0, $self->loc('Error in parameters to Queue->AddWatcher') );
556         }
557     }
558
559     # If the watcher isn't the current user 
560     # and the current user  doesn't have 'ModifyQueueWatcher'
561     # bail
562     else {
563         unless ( $self->CurrentUserHasRight('ModifyQueueWatchers') ) {
564             return ( 0, $self->loc("Permission Denied") );
565         }
566     }
567
568     # }}}
569
570     return ( $self->_AddWatcher(%args) );
571 }
572
573 #This contains the meat of AddWatcher. but can be called from a routine like
574 # Create, which doesn't need the additional acl check
575 sub _AddWatcher {
576     my $self = shift;
577     my %args = (
578         Type   => undef,
579         Silent => undef,
580         PrincipalId => undef,
581         Email => undef,
582         @_
583     );
584
585
586     my $principal = RT::Principal->new($self->CurrentUser);
587     if ($args{'PrincipalId'}) {
588         $principal->Load($args{'PrincipalId'});
589     }
590     elsif ($args{'Email'}) {
591
592         my $user = RT::User->new($self->CurrentUser);
593         $user->LoadByEmail($args{'Email'});
594
595         unless ($user->Id) {
596             $user->Load($args{'Email'});
597         }
598         if ($user->Id) { # If the user exists
599             $principal->Load($user->PrincipalId);
600         } else {
601
602         # if the user doesn't exist, we need to create a new user
603              my $new_user = RT::User->new($RT::SystemUser);
604
605             my ( $Val, $Message ) = $new_user->Create(
606                 Name => $args{'Email'},
607                 EmailAddress => $args{'Email'},
608                 RealName     => $args{'Email'},
609                 Privileged   => 0,
610                 Comments     => 'Autocreated when added as a watcher');
611             unless ($Val) {
612                 $RT::Logger->error("Failed to create user ".$args{'Email'} .": " .$Message);
613                 # Deal with the race condition of two account creations at once
614                 $new_user->LoadByEmail($args{'Email'});
615             }
616             $principal->Load($new_user->PrincipalId);
617         }
618     }
619     # If we can't find this watcher, we need to bail.
620     unless ($principal->Id) {
621         return(0, $self->loc("Could not find or create that user"));
622     }
623
624
625     my $group = RT::Group->new($self->CurrentUser);
626     $group->LoadQueueRoleGroup(Type => $args{'Type'}, Queue => $self->Id);
627     unless ($group->id) {
628         return(0,$self->loc("Group not found"));
629     }
630
631     if ( $group->HasMember( $principal)) {
632
633         return ( 0, $self->loc('That principal is already a [_1] for this queue', $args{'Type'}) );
634     }
635
636
637     my ($m_id, $m_msg) = $group->_AddMember(PrincipalId => $principal->Id);
638     unless ($m_id) {
639         $RT::Logger->error("Failed to add ".$principal->Id." as a member of group ".$group->Id."\n".$m_msg);
640
641         return ( 0, $self->loc('Could not make that principal a [_1] for this queue', $args{'Type'}) );
642     }
643     return ( 1, $self->loc('Added principal as a [_1] for this queue', $args{'Type'}) );
644 }
645
646 # }}}
647
648 # {{{ sub DeleteWatcher
649
650 =head2 DeleteWatcher { Type => TYPE, PrincipalId => PRINCIPAL_ID, Email => EMAIL_ADDRESS }
651
652
653 Deletes a queue  watcher.  Takes two arguments:
654
655 Type  (one of Requestor,Cc,AdminCc)
656
657 and one of
658
659 PrincipalId (an RT::Principal Id of the watcher you want to remove)
660     OR
661 Email (the email address of an existing wathcer)
662
663
664 =cut
665
666
667 sub DeleteWatcher {
668     my $self = shift;
669
670     my %args = ( Type => undef,
671                  PrincipalId => undef,
672                  @_ );
673
674     unless ($args{'PrincipalId'} ) {
675         return(0, $self->loc("No principal specified"));
676     }
677     my $principal = RT::Principal->new($self->CurrentUser);
678     $principal->Load($args{'PrincipalId'});
679
680     # If we can't find this watcher, we need to bail.
681     unless ($principal->Id) {
682         return(0, $self->loc("Could not find that principal"));
683     }
684
685     my $group = RT::Group->new($self->CurrentUser);
686     $group->LoadQueueRoleGroup(Type => $args{'Type'}, Queue => $self->Id);
687     unless ($group->id) {
688         return(0,$self->loc("Group not found"));
689     }
690
691     # {{{ Check ACLS
692     #If the watcher we're trying to add is for the current user
693     if ( $self->CurrentUser->PrincipalId  eq $args{'PrincipalId'}) {
694         #  If it's an AdminCc and they don't have 
695         #   'WatchAsAdminCc' or 'ModifyQueue', bail
696   if ( $args{'Type'} eq 'AdminCc' ) {
697             unless ( $self->CurrentUserHasRight('ModifyQueueWatchers')
698                 or $self->CurrentUserHasRight('WatchAsAdminCc') ) {
699                 return ( 0, $self->loc('Permission Denied'))
700             }
701         }
702
703         #  If it's a Requestor or Cc and they don't have
704         #   'Watch' or 'ModifyQueue', bail
705         elsif ( ( $args{'Type'} eq 'Cc' ) or ( $args{'Type'} eq 'Requestor' ) ) {
706             unless ( $self->CurrentUserHasRight('ModifyQueueWatchers')
707                 or $self->CurrentUserHasRight('Watch') ) {
708                 return ( 0, $self->loc('Permission Denied'))
709             }
710         }
711         else {
712             $RT::Logger->warn( "$self -> DelWatcher got passed a bogus type");
713             return ( 0, $self->loc('Error in parameters to Queue->DelWatcher') );
714         }
715     }
716
717     # If the watcher isn't the current user 
718     # and the current user  doesn't have 'ModifyQueueWathcers' bail
719     else {
720         unless ( $self->CurrentUserHasRight('ModifyQueueWatchers') ) {
721             return ( 0, $self->loc("Permission Denied") );
722         }
723     }
724
725     # }}}
726
727
728     # see if this user is already a watcher.
729
730     unless ( $group->HasMember($principal)) {
731         return ( 0,
732         $self->loc('That principal is not a [_1] for this queue', $args{'Type'}) );
733     }
734
735     my ($m_id, $m_msg) = $group->_DeleteMember($principal->Id);
736     unless ($m_id) {
737         $RT::Logger->error("Failed to delete ".$principal->Id.
738                            " as a member of group ".$group->Id."\n".$m_msg);
739
740         return ( 0,    $self->loc('Could not remove that principal as a [_1] for this queue', $args{'Type'}) );
741     }
742
743     return ( 1, $self->loc("[_1] is no longer a [_2] for this queue.", $principal->Object->Name, $args{'Type'} ));
744 }
745
746 # }}}
747
748 # {{{ AdminCcAddresses
749
750 =head2 AdminCcAddresses
751
752 returns String: All queue AdminCc email addresses as a string
753
754 =cut
755
756 sub AdminCcAddresses {
757     my $self = shift;
758     
759     unless ( $self->CurrentUserHasRight('SeeQueue') ) {
760         return undef;
761     }   
762     
763     return ( $self->AdminCc->MemberEmailAddressesAsString )
764     
765 }   
766
767 # }}}
768
769 # {{{ CcAddresses
770
771 =head2 CcAddresses
772
773 returns String: All queue Ccs as a string of email addresses
774
775 =cut
776
777 sub CcAddresses {
778     my $self = shift;
779
780     unless ( $self->CurrentUserHasRight('SeeQueue') ) {
781         return undef;
782     }
783
784     return ( $self->Cc->MemberEmailAddressesAsString);
785
786 }
787 # }}}
788
789
790 # {{{ sub Cc
791
792 =head2 Cc
793
794 Takes nothing.
795 Returns an RT::Group object which contains this Queue's Ccs.
796 If the user doesn't have "ShowQueue" permission, returns an empty group
797
798 =cut
799
800 sub Cc {
801     my $self = shift;
802
803     my $group = RT::Group->new($self->CurrentUser);
804     if ( $self->CurrentUserHasRight('SeeQueue') ) {
805         $group->LoadQueueRoleGroup(Type => 'Cc', Queue => $self->Id);
806     }
807     return ($group);
808
809 }
810
811 # }}}
812
813 # {{{ sub AdminCc
814
815 =head2 AdminCc
816
817 Takes nothing.
818 Returns an RT::Group object which contains this Queue's AdminCcs.
819 If the user doesn't have "ShowQueue" permission, returns an empty group
820
821 =cut
822
823 sub AdminCc {
824     my $self = shift;
825
826     my $group = RT::Group->new($self->CurrentUser);
827     if ( $self->CurrentUserHasRight('SeeQueue') ) {
828         $group->LoadQueueRoleGroup(Type => 'AdminCc', Queue => $self->Id);
829     }
830     return ($group);
831
832 }
833
834 # }}}
835
836 # {{{ IsWatcher, IsCc, IsAdminCc
837
838 # {{{ sub IsWatcher
839 # a generic routine to be called by IsRequestor, IsCc and IsAdminCc
840
841 =head2 IsWatcher { Type => TYPE, PrincipalId => PRINCIPAL_ID }
842
843 Takes a param hash with the attributes Type and PrincipalId
844
845 Type is one of Requestor, Cc, AdminCc and Owner
846
847 PrincipalId is an RT::Principal id 
848
849 Returns true if that principal is a member of the group Type for this queue
850
851
852 =cut
853
854 sub IsWatcher {
855     my $self = shift;
856
857     my %args = ( Type  => 'Cc',
858         PrincipalId    => undef,
859         @_
860     );
861
862     # Load the relevant group. 
863     my $group = RT::Group->new($self->CurrentUser);
864     $group->LoadQueueRoleGroup(Type => $args{'Type'}, Queue => $self->id);
865     # Ask if it has the member in question
866
867     my $principal = RT::Principal->new($self->CurrentUser);
868     $principal->Load($args{'PrincipalId'});
869     unless ($principal->Id) {
870         return (undef);
871     }
872
873     return ($group->HasMemberRecursively($principal));
874 }
875
876 # }}}
877
878
879 # {{{ sub IsCc
880
881 =head2 IsCc PRINCIPAL_ID
882
883   Takes an RT::Principal id.
884   Returns true if the principal is a requestor of the current queue.
885
886
887 =cut
888
889 sub IsCc {
890     my $self = shift;
891     my $cc   = shift;
892
893     return ( $self->IsWatcher( Type => 'Cc', PrincipalId => $cc ) );
894
895 }
896
897 # }}}
898
899 # {{{ sub IsAdminCc
900
901 =head2 IsAdminCc PRINCIPAL_ID
902
903   Takes an RT::Principal id.
904   Returns true if the principal is a requestor of the current queue.
905
906 =cut
907
908 sub IsAdminCc {
909     my $self   = shift;
910     my $person = shift;
911
912     return ( $self->IsWatcher( Type => 'AdminCc', PrincipalId => $person ) );
913
914 }
915
916 # }}}
917
918
919 # }}}
920
921
922
923
924
925 # }}}
926
927 # {{{ ACCESS CONTROL
928
929 # {{{ sub _Set
930 sub _Set {
931     my $self = shift;
932
933     unless ( $self->CurrentUserHasRight('AdminQueue') ) {
934         return ( 0, $self->loc('Permission Denied') );
935     }
936     return ( $self->SUPER::_Set(@_) );
937 }
938
939 # }}}
940
941 # {{{ sub _Value
942
943 sub _Value {
944     my $self = shift;
945
946     unless ( $self->CurrentUserHasRight('SeeQueue') ) {
947         return (undef);
948     }
949
950     return ( $self->__Value(@_) );
951 }
952
953 # }}}
954
955 # {{{ sub CurrentUserHasRight
956
957 =head2 CurrentUserHasRight
958
959 Takes one argument. A textual string with the name of the right we want to check.
960 Returns true if the current user has that right for this queue.
961 Returns undef otherwise.
962
963 =cut
964
965 sub CurrentUserHasRight {
966     my $self  = shift;
967     my $right = shift;
968
969     return (
970         $self->HasRight(
971             Principal => $self->CurrentUser,
972             Right     => "$right"
973           )
974     );
975
976 }
977
978 # }}}
979
980 # {{{ sub HasRight
981
982 =head2 HasRight
983
984 Takes a param hash with the fields 'Right' and 'Principal'.
985 Principal defaults to the current user.
986 Returns true if the principal has that right for this queue.
987 Returns undef otherwise.
988
989 =cut
990
991 # TAKES: Right and optional "Principal" which defaults to the current user
992 sub HasRight {
993     my $self = shift;
994     my %args = (
995         Right     => undef,
996         Principal => $self->CurrentUser,
997         @_
998     );
999     unless ( defined $args{'Principal'} ) {
1000         $RT::Logger->debug("Principal undefined in Queue::HasRight");
1001
1002     }
1003     return (
1004         $args{'Principal'}->HasRight(
1005             Object => $self,
1006             Right    => $args{'Right'}
1007           )
1008     );
1009 }
1010
1011 # }}}
1012
1013 # }}}
1014
1015 1;