1 # BEGIN BPS TAGGED BLOCK {{{
5 # This software is Copyright (c) 1996-2007 Best Practical Solutions, LLC
6 # <jesse@bestpractical.com>
8 # (Except where explicitly superseded by other copyright notices)
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
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.
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/copyleft/gpl.html.
30 # CONTRIBUTION SUBMISSION POLICY:
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.)
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.
47 # END BPS TAGGED BLOCK }}}
50 RT::Queue - an RT Queue object
73 no warnings qw(redefine);
75 use vars qw(@DEFAULT_ACTIVE_STATUS @DEFAULT_INACTIVE_STATUS $RIGHTS);
79 use RT::Interface::Email;
81 @DEFAULT_ACTIVE_STATUS = qw(new open stalled);
82 @DEFAULT_INACTIVE_STATUS = qw(resolved rejected deleted);
84 # $self->loc('new'); # For the string extractor to get a string to localize
85 # $self->loc('open'); # For the string extractor to get a string to localize
86 # $self->loc('stalled'); # For the string extractor to get a string to localize
87 # $self->loc('resolved'); # For the string extractor to get a string to localize
88 # $self->loc('rejected'); # For the string extractor to get a string to localize
89 # $self->loc('deleted'); # For the string extractor to get a string to localize
93 SeeQueue => 'Can this principal see this queue', # loc_pair
94 AdminQueue => 'Create, delete and modify queues', # loc_pair
95 ShowACL => 'Display Access Control List', # loc_pair
96 ModifyACL => 'Modify Access Control List', # loc_pair
97 ModifyQueueWatchers => 'Modify the queue watchers', # loc_pair
98 AssignCustomFields => 'Assign and remove custom fields', # loc_pair
99 ModifyTemplate => 'Modify Scrip templates for this queue', # loc_pair
100 ShowTemplate => 'Display Scrip templates for this queue', # loc_pair
102 ModifyScrips => 'Modify Scrips for this queue', # loc_pair
103 ShowScrips => 'Display Scrips for this queue', # loc_pair
105 ShowTicket => 'See ticket summaries', # loc_pair
106 ShowTicketComments => 'See ticket private commentary', # loc_pair
107 ShowOutgoingEmail => 'See exact outgoing email messages and their recipeients', # loc_pair
109 Watch => 'Sign up as a ticket Requestor or ticket or queue Cc', # loc_pair
110 WatchAsAdminCc => 'Sign up as a ticket or queue AdminCc', # loc_pair
111 CreateTicket => 'Create tickets in this queue', # loc_pair
112 ReplyToTicket => 'Reply to tickets', # loc_pair
113 CommentOnTicket => 'Comment on tickets', # loc_pair
114 OwnTicket => 'Own tickets', # loc_pair
115 ModifyTicket => 'Modify tickets', # loc_pair
116 DeleteTicket => 'Delete tickets', # loc_pair
117 TakeTicket => 'Take tickets', # loc_pair
118 StealTicket => 'Steal tickets', # loc_pair
122 # Tell RT::ACE that this sort of object can get acls granted
123 $RT::ACE::OBJECT_TYPES{'RT::Queue'} = 1;
125 # TODO: This should be refactored out into an RT::ACLedObject or something
126 # stuff the rights into a hash of rights that can exist.
128 foreach my $right ( keys %{$RIGHTS} ) {
129 $RT::ACE::LOWERCASERIGHTNAMES{ lc $right } = $right;
135 my %args = ( Target => '',
141 unless ( $self->CurrentUserHasRight('ModifyQueue') ) {
142 return ( 0, $self->loc("Permission Denied") );
145 return $self->SUPER::_AddLink(%args);
158 unless ( $self->CurrentUserHasRight('ModifyQueue') ) {
159 $RT::Logger->debug("No permission to delete links\n");
160 return ( 0, $self->loc('Permission Denied'))
163 return $self->SUPER::_DeleteLink(%args);
166 =head2 AvailableRights
168 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
172 sub AvailableRights {
177 # {{{ ActiveStatusArray
179 =head2 ActiveStatusArray
181 Returns an array of all ActiveStatuses for this queue
185 sub ActiveStatusArray {
187 if (@RT::ActiveStatus) {
188 return (@RT::ActiveStatus)
190 $RT::Logger->warning("RT::ActiveStatus undefined, falling back to deprecated defaults");
191 return (@DEFAULT_ACTIVE_STATUS);
197 # {{{ InactiveStatusArray
199 =head2 InactiveStatusArray
201 Returns an array of all InactiveStatuses for this queue
205 sub InactiveStatusArray {
207 if (@RT::InactiveStatus) {
208 return (@RT::InactiveStatus)
210 $RT::Logger->warning("RT::InactiveStatus undefined, falling back to deprecated defaults");
211 return (@DEFAULT_INACTIVE_STATUS);
221 Returns an array of all statuses for this queue
227 return ($self->ActiveStatusArray(), $self->InactiveStatusArray());
234 =head2 IsValidStatus VALUE
236 Returns true if VALUE is a valid status. Otherwise, returns 0.
240 my $q = RT::Queue->new($RT::SystemUser);
241 ok($q->IsValidStatus('new')== 1, 'New is a valid status');
242 ok($q->IsValidStatus('f00')== 0, 'f00 is not a valid status');
252 my $retval = grep ( $_ eq $value, $self->StatusArray );
261 =head2 IsActiveStatus VALUE
263 Returns true if VALUE is a Active status. Otherwise, returns 0
267 my $q = RT::Queue->new($RT::SystemUser);
268 ok($q->IsActiveStatus('new')== 1, 'New is a Active status');
269 ok($q->IsActiveStatus('rejected')== 0, 'Rejected is an inactive status');
270 ok($q->IsActiveStatus('f00')== 0, 'f00 is not a Active status');
280 my $retval = grep ( $_ eq $value, $self->ActiveStatusArray );
287 # {{{ IsInactiveStatus
289 =head2 IsInactiveStatus VALUE
291 Returns true if VALUE is a Inactive status. Otherwise, returns 0
295 my $q = RT::Queue->new($RT::SystemUser);
296 ok($q->IsInactiveStatus('new')== 0, 'New is a Active status');
297 ok($q->IsInactiveStatus('rejected')== 1, 'rejeected is an Inactive status');
298 ok($q->IsInactiveStatus('f00')== 0, 'f00 is not a Active status');
304 sub IsInactiveStatus {
308 my $retval = grep ( $_ eq $value, $self->InactiveStatusArray );
323 Arguments: ARGS is a hash of named parameters. Valid parameters are:
333 If you pass the ACL check, it creates the queue and returns its queue id.
337 my $queue = RT::Queue->new($RT::SystemUser);
338 my ($id, $val) = $queue->Create( Name => 'Test1');
341 ($id, $val) = $queue->Create( Name => '66');
352 CorrespondAddress => '',
354 CommentAddress => '',
355 InitialPriority => "0",
356 FinalPriority => "0",
361 unless ( $self->CurrentUser->HasRight(Right => 'AdminQueue', Object => $RT::System) )
363 return ( 0, $self->loc("No permission to create queues") );
366 unless ( $self->ValidateName( $args{'Name'} ) ) {
367 return ( 0, $self->loc('Queue already exists') );
370 #TODO better input validation
371 $RT::Handle->BeginTransaction();
373 my $id = $self->SUPER::Create(%args);
375 $RT::Handle->Rollback();
376 return ( 0, $self->loc('Queue could not be created') );
379 my $create_ret = $self->_CreateQueueGroups();
380 unless ($create_ret) {
381 $RT::Handle->Rollback();
382 return ( 0, $self->loc('Queue could not be created') );
385 $RT::Handle->Commit();
386 return ( $id, $self->loc("Queue created") );
396 $self->loc('Deleting this object would break referential integrity') );
401 # {{{ sub SetDisabled
406 1 will cause this queue to no longer be available for tickets.
407 0 will re-enable this queue.
417 Takes either a numerical id or a textual Name and loads the specified queue.
424 my $identifier = shift;
425 if ( !$identifier ) {
429 if ( $identifier =~ /^(\d+)$/ ) {
430 $self->SUPER::LoadById($identifier);
433 $self->LoadByCols( Name => $identifier );
436 return ( $self->Id );
442 # {{{ sub ValidateName
444 =head2 ValidateName NAME
446 Takes a queue name. Returns true if it's an ok name for
447 a new queue. Returns undef if there's already a queue by that name.
455 my $tempqueue = new RT::Queue($RT::SystemUser);
456 $tempqueue->Load($name);
458 #If this queue exists, return undef
459 if ( $tempqueue->Name() && $tempqueue->id != $self->id) {
463 #If the queue doesn't exist, return 1
465 return ($self->SUPER::ValidateName($name));
476 Returns an RT::Templates object of all of this queue's templates.
483 my $templates = RT::Templates->new( $self->CurrentUser );
485 if ( $self->CurrentUserHasRight('ShowTemplate') ) {
486 $templates->LimitToQueue( $self->id );
494 # {{{ Dealing with custom fields
498 =head2 CustomField NAME
500 Load the queue-specific custom field named NAME
507 my $cf = RT::CustomField->new($self->CurrentUser);
508 $cf->LoadByNameAndQueue(Name => $name, Queue => $self->Id);
517 Returns an RT::CustomFields object containing all global custom fields, as well as those tied to this queue
521 # XXX TODO - this should become TicketCustomFields
525 warn "Queue->CustomFields is deprecated, use Queue->TicketCustomFields instead at (". join(":",caller).")";
526 return $self->TicketCustomFields(@_);
529 sub TicketCustomFields {
532 my $cfs = RT::CustomFields->new( $self->CurrentUser );
533 if ( $self->CurrentUserHasRight('SeeQueue') ) {
534 $cfs->LimitToGlobalOrObjectId( $self->Id );
535 $cfs->LimitToLookupType( 'RT::Queue-RT::Ticket' );
540 sub TicketTransactionCustomFields {
543 my $cfs = RT::CustomFields->new( $self->CurrentUser );
544 if ( $self->CurrentUserHasRight('SeeQueue') ) {
545 $cfs->LimitToGlobalOrObjectId( $self->Id );
546 $cfs->LimitToLookupType( 'RT::Queue-RT::Ticket-RT::Transaction' );
556 # {{{ Routines dealing with watchers.
558 # {{{ _CreateQueueGroups
560 =head2 _CreateQueueGroups
562 Create the ticket groups and links for this ticket.
563 This routine expects to be called from Ticket->Create _inside of a transaction_
565 It will create four groups for this ticket: Requestor, Cc, AdminCc and Owner.
567 It will return true on success and undef on failure.
571 my $Queue = RT::Queue->new($RT::SystemUser); my ($id, $msg) = $Queue->Create(Name => "Foo",
573 ok ($id, "Foo $id was created");
574 ok(my $group = RT::Group->new($RT::SystemUser));
575 ok($group->LoadQueueRoleGroup(Queue => $id, Type=> 'Cc'));
576 ok ($group->Id, "Found the requestors object for this Queue");
579 ok ((my $add_id, $add_msg) = $Queue->AddWatcher(Type => 'Cc', Email => 'bob@fsck.com'), "Added bob at fsck.com as a requestor");
580 ok ($add_id, "Add succeeded: ($add_msg)");
581 ok(my $bob = RT::User->new($RT::SystemUser), "Creating a bob rt::user");
582 $bob->LoadByEmail('bob@fsck.com');
583 ok($bob->Id, "Found the bob rt user");
584 ok ($Queue->IsWatcher(Type => 'Cc', PrincipalId => $bob->PrincipalId), "The Queue actually has bob at fsck.com as a requestor");;
585 ok ((my $add_id, $add_msg) = $Queue->DeleteWatcher(Type =>'Cc', Email => 'bob@fsck.com'), "Added bob at fsck.com as a requestor");
586 ok (!$Queue->IsWatcher(Type => 'Cc', Principal => $bob->PrincipalId), "The Queue no longer has bob at fsck.com as a requestor");;
589 $group = RT::Group->new($RT::SystemUser);
590 ok($group->LoadQueueRoleGroup(Queue => $id, Type=> 'Cc'));
591 ok ($group->Id, "Found the cc object for this Queue");
592 $group = RT::Group->new($RT::SystemUser);
593 ok($group->LoadQueueRoleGroup(Queue => $id, Type=> 'AdminCc'));
594 ok ($group->Id, "Found the AdminCc object for this Queue");
601 sub _CreateQueueGroups {
604 my @types = qw(Cc AdminCc Requestor Owner);
606 foreach my $type (@types) {
607 my $type_obj = RT::Group->new($self->CurrentUser);
608 my ($id, $msg) = $type_obj->CreateRoleGroup(Instance => $self->Id,
610 Domain => 'RT::Queue-Role');
612 $RT::Logger->error("Couldn't create a Queue group of type '$type' for ticket ".
613 $self->Id.": ".$msg);
628 AddWatcher takes a parameter hash. The keys are as follows:
630 Type One of Requestor, Cc, AdminCc
632 PrinicpalId The RT::Principal id of the user or group that's being added as a watcher
633 Email The email address of the new watcher. If a user with this
634 email address can't be found, a new nonprivileged user will be created.
636 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.
638 Returns a tuple of (status/id, message).
646 PrincipalId => undef,
652 #If the watcher we're trying to add is for the current user
653 if ( $self->CurrentUser->PrincipalId eq $args{'PrincipalId'}) {
654 # If it's an AdminCc and they don't have
655 # 'WatchAsAdminCc' or 'ModifyTicket', bail
656 if ( $args{'Type'} eq 'AdminCc' ) {
657 unless ( $self->CurrentUserHasRight('ModifyQueueWatchers')
658 or $self->CurrentUserHasRight('WatchAsAdminCc') ) {
659 return ( 0, $self->loc('Permission Denied'))
663 # If it's a Requestor or Cc and they don't have
664 # 'Watch' or 'ModifyTicket', bail
665 elsif ( ( $args{'Type'} eq 'Cc' ) or ( $args{'Type'} eq 'Requestor' ) ) {
667 unless ( $self->CurrentUserHasRight('ModifyQueueWatchers')
668 or $self->CurrentUserHasRight('Watch') ) {
669 return ( 0, $self->loc('Permission Denied'))
673 $RT::Logger->warning( "$self -> AddWatcher got passed a bogus type");
674 return ( 0, $self->loc('Error in parameters to Queue->AddWatcher') );
678 # If the watcher isn't the current user
679 # and the current user doesn't have 'ModifyQueueWatcher'
682 unless ( $self->CurrentUserHasRight('ModifyQueueWatchers') ) {
683 return ( 0, $self->loc("Permission Denied") );
689 return ( $self->_AddWatcher(%args) );
692 #This contains the meat of AddWatcher. but can be called from a routine like
693 # Create, which doesn't need the additional acl check
699 PrincipalId => undef,
705 my $principal = RT::Principal->new($self->CurrentUser);
706 if ($args{'PrincipalId'}) {
707 $principal->Load($args{'PrincipalId'});
709 elsif ($args{'Email'}) {
711 my $user = RT::User->new($self->CurrentUser);
712 $user->LoadByEmail($args{'Email'});
715 $user->Load($args{'Email'});
717 if ($user->Id) { # If the user exists
718 $principal->Load($user->PrincipalId);
721 # if the user doesn't exist, we need to create a new user
722 my $new_user = RT::User->new($RT::SystemUser);
724 my ( $Address, $Name ) =
725 RT::Interface::Email::ParseAddressFromHeader($args{'Email'});
727 my ( $Val, $Message ) = $new_user->Create(
729 EmailAddress => $Address,
732 Comments => 'Autocreated when added as a watcher');
734 $RT::Logger->error("Failed to create user ".$args{'Email'} .": " .$Message);
735 # Deal with the race condition of two account creations at once
736 $new_user->LoadByEmail($args{'Email'});
738 $principal->Load($new_user->PrincipalId);
741 # If we can't find this watcher, we need to bail.
742 unless ($principal->Id) {
743 return(0, $self->loc("Could not find or create that user"));
747 my $group = RT::Group->new($self->CurrentUser);
748 $group->LoadQueueRoleGroup(Type => $args{'Type'}, Queue => $self->Id);
749 unless ($group->id) {
750 return(0,$self->loc("Group not found"));
753 if ( $group->HasMember( $principal)) {
755 return ( 0, $self->loc('That principal is already a [_1] for this queue', $args{'Type'}) );
759 my ($m_id, $m_msg) = $group->_AddMember(PrincipalId => $principal->Id);
761 $RT::Logger->error("Failed to add ".$principal->Id." as a member of group ".$group->Id."\n".$m_msg);
763 return ( 0, $self->loc('Could not make that principal a [_1] for this queue', $args{'Type'}) );
765 return ( 1, $self->loc('Added principal as a [_1] for this queue', $args{'Type'}) );
770 # {{{ sub DeleteWatcher
772 =head2 DeleteWatcher { Type => TYPE, PrincipalId => PRINCIPAL_ID, Email => EMAIL_ADDRESS }
775 Deletes a queue watcher. Takes two arguments:
777 Type (one of Requestor,Cc,AdminCc)
781 PrincipalId (an RT::Principal Id of the watcher you want to remove)
783 Email (the email address of an existing wathcer)
792 my %args = ( Type => undef,
793 PrincipalId => undef,
796 unless ($args{'PrincipalId'} ) {
797 return(0, $self->loc("No principal specified"));
799 my $principal = RT::Principal->new($self->CurrentUser);
800 $principal->Load($args{'PrincipalId'});
802 # If we can't find this watcher, we need to bail.
803 unless ($principal->Id) {
804 return(0, $self->loc("Could not find that principal"));
807 my $group = RT::Group->new($self->CurrentUser);
808 $group->LoadQueueRoleGroup(Type => $args{'Type'}, Queue => $self->Id);
809 unless ($group->id) {
810 return(0,$self->loc("Group not found"));
814 #If the watcher we're trying to add is for the current user
815 if ( $self->CurrentUser->PrincipalId eq $args{'PrincipalId'}) {
816 # If it's an AdminCc and they don't have
817 # 'WatchAsAdminCc' or 'ModifyQueue', bail
818 if ( $args{'Type'} eq 'AdminCc' ) {
819 unless ( $self->CurrentUserHasRight('ModifyQueueWatchers')
820 or $self->CurrentUserHasRight('WatchAsAdminCc') ) {
821 return ( 0, $self->loc('Permission Denied'))
825 # If it's a Requestor or Cc and they don't have
826 # 'Watch' or 'ModifyQueue', bail
827 elsif ( ( $args{'Type'} eq 'Cc' ) or ( $args{'Type'} eq 'Requestor' ) ) {
828 unless ( $self->CurrentUserHasRight('ModifyQueueWatchers')
829 or $self->CurrentUserHasRight('Watch') ) {
830 return ( 0, $self->loc('Permission Denied'))
834 $RT::Logger->warning( "$self -> DeleteWatcher got passed a bogus type");
835 return ( 0, $self->loc('Error in parameters to Queue->DeleteWatcher') );
839 # If the watcher isn't the current user
840 # and the current user doesn't have 'ModifyQueueWathcers' bail
842 unless ( $self->CurrentUserHasRight('ModifyQueueWatchers') ) {
843 return ( 0, $self->loc("Permission Denied") );
850 # see if this user is already a watcher.
852 unless ( $group->HasMember($principal)) {
854 $self->loc('That principal is not a [_1] for this queue', $args{'Type'}) );
857 my ($m_id, $m_msg) = $group->_DeleteMember($principal->Id);
859 $RT::Logger->error("Failed to delete ".$principal->Id.
860 " as a member of group ".$group->Id."\n".$m_msg);
862 return ( 0, $self->loc('Could not remove that principal as a [_1] for this queue', $args{'Type'}) );
865 return ( 1, $self->loc("[_1] is no longer a [_2] for this queue.", $principal->Object->Name, $args{'Type'} ));
870 # {{{ AdminCcAddresses
872 =head2 AdminCcAddresses
874 returns String: All queue AdminCc email addresses as a string
878 sub AdminCcAddresses {
881 unless ( $self->CurrentUserHasRight('SeeQueue') ) {
885 return ( $self->AdminCc->MemberEmailAddressesAsString )
895 returns String: All queue Ccs as a string of email addresses
902 unless ( $self->CurrentUserHasRight('SeeQueue') ) {
906 return ( $self->Cc->MemberEmailAddressesAsString);
917 Returns an RT::Group object which contains this Queue's Ccs.
918 If the user doesn't have "ShowQueue" permission, returns an empty group
925 my $group = RT::Group->new($self->CurrentUser);
926 if ( $self->CurrentUserHasRight('SeeQueue') ) {
927 $group->LoadQueueRoleGroup(Type => 'Cc', Queue => $self->Id);
940 Returns an RT::Group object which contains this Queue's AdminCcs.
941 If the user doesn't have "ShowQueue" permission, returns an empty group
948 my $group = RT::Group->new($self->CurrentUser);
949 if ( $self->CurrentUserHasRight('SeeQueue') ) {
950 $group->LoadQueueRoleGroup(Type => 'AdminCc', Queue => $self->Id);
958 # {{{ IsWatcher, IsCc, IsAdminCc
961 # a generic routine to be called by IsRequestor, IsCc and IsAdminCc
963 =head2 IsWatcher { Type => TYPE, PrincipalId => PRINCIPAL_ID }
965 Takes a param hash with the attributes Type and PrincipalId
967 Type is one of Requestor, Cc, AdminCc and Owner
969 PrincipalId is an RT::Principal id
971 Returns true if that principal is a member of the group Type for this queue
979 my %args = ( Type => 'Cc',
980 PrincipalId => undef,
984 # Load the relevant group.
985 my $group = RT::Group->new($self->CurrentUser);
986 $group->LoadQueueRoleGroup(Type => $args{'Type'}, Queue => $self->id);
987 # Ask if it has the member in question
989 my $principal = RT::Principal->new($self->CurrentUser);
990 $principal->Load($args{'PrincipalId'});
991 unless ($principal->Id) {
995 return ($group->HasMemberRecursively($principal));
1003 =head2 IsCc PRINCIPAL_ID
1005 Takes an RT::Principal id.
1006 Returns true if the principal is a requestor of the current queue.
1015 return ( $self->IsWatcher( Type => 'Cc', PrincipalId => $cc ) );
1023 =head2 IsAdminCc PRINCIPAL_ID
1025 Takes an RT::Principal id.
1026 Returns true if the principal is a requestor of the current queue.
1034 return ( $self->IsWatcher( Type => 'AdminCc', PrincipalId => $person ) );
1049 # {{{ ACCESS CONTROL
1055 unless ( $self->CurrentUserHasRight('AdminQueue') ) {
1056 return ( 0, $self->loc('Permission Denied') );
1058 return ( $self->SUPER::_Set(@_) );
1068 unless ( $self->CurrentUserHasRight('SeeQueue') ) {
1072 return ( $self->__Value(@_) );
1077 # {{{ sub CurrentUserHasRight
1079 =head2 CurrentUserHasRight
1081 Takes one argument. A textual string with the name of the right we want to check.
1082 Returns true if the current user has that right for this queue.
1083 Returns undef otherwise.
1087 sub CurrentUserHasRight {
1093 Principal => $self->CurrentUser,
1106 Takes a param hash with the fields 'Right' and 'Principal'.
1107 Principal defaults to the current user.
1108 Returns true if the principal has that right for this queue.
1109 Returns undef otherwise.
1113 # TAKES: Right and optional "Principal" which defaults to the current user
1118 Principal => $self->CurrentUser,
1121 unless ( defined $args{'Principal'} ) {
1122 $RT::Logger->debug("Principal undefined in Queue::HasRight");
1126 $args{'Principal'}->HasRight(
1127 Object => $self->Id ? $self : $RT::System,
1128 Right => $args{'Right'}