1 # BEGIN BPS TAGGED BLOCK {{{
5 # This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC
6 # <sales@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/licenses/old-licenses/gpl-2.0.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 }}}
51 RT::Queue - an RT Queue object
70 use base 'RT::Record';
78 use RT::Interface::Email;
80 our @DEFAULT_ACTIVE_STATUS = qw(new open stalled);
81 our @DEFAULT_INACTIVE_STATUS = qw(resolved rejected deleted);
83 # $self->loc('new'); # For the string extractor to get a string to localize
84 # $self->loc('open'); # For the string extractor to get a string to localize
85 # $self->loc('stalled'); # For the string extractor to get a string to localize
86 # $self->loc('resolved'); # For the string extractor to get a string to localize
87 # $self->loc('rejected'); # For the string extractor to get a string to localize
88 # $self->loc('deleted'); # For the string extractor to get a string to localize
92 SeeQueue => 'View queue', # loc_pair
93 AdminQueue => 'Create, modify and delete queue', # loc_pair
94 ShowACL => 'Display Access Control List', # loc_pair
95 ModifyACL => 'Create, modify and delete Access Control List entries', # loc_pair
96 ModifyQueueWatchers => 'Modify queue watchers', # loc_pair
97 SeeCustomField => 'View custom field values', # loc_pair
98 ModifyCustomField => 'Modify custom field values', # loc_pair
99 AssignCustomFields => 'Assign and remove queue custom fields', # loc_pair
100 ModifyTemplate => 'Modify Scrip templates', # loc_pair
101 ShowTemplate => 'View Scrip templates', # loc_pair
103 ModifyScrips => 'Modify Scrips', # loc_pair
104 ShowScrips => 'View Scrips', # loc_pair
106 ShowTicket => 'View ticket summaries', # loc_pair
107 ShowTicketComments => 'View ticket private commentary', # loc_pair
108 ShowOutgoingEmail => 'View exact outgoing email messages and their recipients', # loc_pair
110 Watch => 'Sign up as a ticket Requestor or ticket or queue Cc', # loc_pair
111 WatchAsAdminCc => 'Sign up as a ticket or queue AdminCc', # loc_pair
112 CreateTicket => 'Create tickets', # loc_pair
113 ReplyToTicket => 'Reply to tickets', # loc_pair
114 CommentOnTicket => 'Comment on tickets', # loc_pair
115 OwnTicket => 'Own tickets', # loc_pair
116 ModifyTicket => 'Modify tickets', # loc_pair
117 DeleteTicket => 'Delete tickets', # loc_pair
118 TakeTicket => 'Take tickets', # loc_pair
119 StealTicket => 'Steal tickets', # loc_pair
121 ForwardMessage => 'Forward messages outside of RT', # loc_pair
124 our $RIGHT_CATEGORIES = {
125 SeeQueue => 'General',
126 AdminQueue => 'Admin',
128 ModifyACL => 'Admin',
129 ModifyQueueWatchers => 'Admin',
130 SeeCustomField => 'General',
131 ModifyCustomField => 'Staff',
132 AssignCustomFields => 'Admin',
133 ModifyTemplate => 'Admin',
134 ShowTemplate => 'Admin',
135 ModifyScrips => 'Admin',
136 ShowScrips => 'Admin',
137 ShowTicket => 'General',
138 ShowTicketComments => 'Staff',
139 ShowOutgoingEmail => 'Staff',
141 WatchAsAdminCc => 'Staff',
142 CreateTicket => 'General',
143 ReplyToTicket => 'General',
144 CommentOnTicket => 'General',
145 OwnTicket => 'Staff',
146 ModifyTicket => 'Staff',
147 DeleteTicket => 'Staff',
148 TakeTicket => 'Staff',
149 StealTicket => 'Staff',
150 ForwardMessage => 'Staff',
153 # Tell RT::ACE that this sort of object can get acls granted
154 $RT::ACE::OBJECT_TYPES{'RT::Queue'} = 1;
156 # TODO: This should be refactored out into an RT::ACLedObject or something
157 # stuff the rights into a hash of rights that can exist.
159 __PACKAGE__->AddRights(%$RIGHTS);
160 __PACKAGE__->AddRightCategories(%$RIGHT_CATEGORIES);
161 require RT::Lifecycle;
163 =head2 AddRights C<RIGHT>, C<DESCRIPTION> [, ...]
165 Adds the given rights to the list of possible rights. This method
166 should be called during server startup, not at runtime.
173 $RIGHTS = { %$RIGHTS, %new };
174 %RT::ACE::LOWERCASERIGHTNAMES = ( %RT::ACE::LOWERCASERIGHTNAMES,
175 map { lc($_) => $_ } keys %new);
178 =head2 AddRightCategories C<RIGHT>, C<CATEGORY> [, ...]
180 Adds the given right and category pairs to the list of right categories. This
181 method should be called during server startup, not at runtime.
185 sub AddRightCategories {
186 my $self = shift if ref $_[0] or $_[0] eq __PACKAGE__;
188 $RIGHT_CATEGORIES = { %$RIGHT_CATEGORIES, %new };
193 my %args = ( Target => '',
199 unless ( $self->CurrentUserHasRight('ModifyQueue') ) {
200 return ( 0, $self->loc("Permission Denied") );
203 return $self->SUPER::_AddLink(%args);
216 unless ( $self->CurrentUserHasRight('ModifyQueue') ) {
217 $RT::Logger->debug("No permission to delete links");
218 return ( 0, $self->loc('Permission Denied'))
221 return $self->SUPER::_DeleteLink(%args);
224 =head2 AvailableRights
226 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
230 sub AvailableRights {
235 =head2 RightCategories
237 Returns a hashref where the keys are rights for this type of object and the
238 values are the category (General, Staff, Admin) the right falls into.
242 sub RightCategories {
243 return $RIGHT_CATEGORIES;
249 unless (ref $self && $self->id) {
250 return RT::Lifecycle->Load('')
253 my $name = $self->_Value( Lifecycle => @_ );
256 my $res = RT::Lifecycle->Load( $name );
258 $RT::Logger->error("Lifecycle '$name' for queue '".$self->Name."' doesn't exist");
259 return RT::Lifecycle->Load('default');
266 my $value = shift || 'default';
268 return ( 0, $self->loc( '[_1] is not a valid lifecycle', $value ) )
269 unless $self->ValidateLifecycle($value);
271 return $self->_Set( Field => 'Lifecycle', Value => $value, @_ );
274 =head2 ValidateLifecycle NAME
276 Takes a lifecycle name. Returns true if it's an ok name and such
277 lifecycle is configured. Returns undef otherwise.
281 sub ValidateLifecycle {
284 return undef unless RT::Lifecycle->Load( $value );
289 =head2 ActiveStatusArray
291 Returns an array of all ActiveStatuses for this queue
295 sub ActiveStatusArray {
297 return $self->Lifecycle->Valid('initial', 'active');
300 =head2 InactiveStatusArray
302 Returns an array of all InactiveStatuses for this queue
306 sub InactiveStatusArray {
308 return $self->Lifecycle->Inactive;
313 Returns an array of all statuses for this queue
319 return $self->Lifecycle->Valid( @_ );
322 =head2 IsValidStatus value
324 Returns true if value is a valid status. Otherwise, returns 0.
330 return $self->Lifecycle->IsValid( shift );
333 =head2 IsActiveStatus value
335 Returns true if value is a Active status. Otherwise, returns 0
341 return $self->Lifecycle->IsValid( shift, 'initial', 'active');
346 =head2 IsInactiveStatus value
348 Returns true if value is a Inactive status. Otherwise, returns 0
353 sub IsInactiveStatus {
355 return $self->Lifecycle->IsInactive( shift );
365 Arguments: ARGS is a hash of named parameters. Valid parameters are:
375 If you pass the ACL check, it creates the queue and returns its queue id.
385 CorrespondAddress => '',
386 CommentAddress => '',
387 Lifecycle => 'default',
389 InitialPriority => 0,
395 _RecordTransaction => 1,
399 unless ( $self->CurrentUser->HasRight(Right => 'AdminQueue', Object => $RT::System) )
401 return ( 0, $self->loc("No permission to create queues") );
405 my ($val, $msg) = $self->_ValidateName( $args{'Name'} );
406 return ($val, $msg) unless $val;
409 $args{'Lifecycle'} ||= 'default';
411 return ( 0, $self->loc('[_1] is not a valid lifecycle', $args{'Lifecycle'} ) )
412 unless $self->ValidateLifecycle( $args{'Lifecycle'} );
414 my %attrs = map {$_ => 1} $self->ReadableAttributes;
416 #TODO better input validation
417 $RT::Handle->BeginTransaction();
418 my $id = $self->SUPER::Create( map { $_ => $args{$_} } grep exists $args{$_}, keys %attrs );
420 $RT::Handle->Rollback();
421 return ( 0, $self->loc('Queue could not be created') );
424 my $create_ret = $self->_CreateQueueGroups();
425 unless ($create_ret) {
426 $RT::Handle->Rollback();
427 return ( 0, $self->loc('Queue could not be created') );
429 if ( $args{'_RecordTransaction'} ) {
430 $self->_NewTransaction( Type => "Create" );
434 for my $attr (qw/Sign SignAuto Encrypt/) {
435 next unless defined $args{$attr};
436 my $set = "Set" . $attr;
437 my ($status, $msg) = $self->$set( $args{$attr} );
438 $RT::Logger->error("Couldn't set attribute '$attr': $msg")
442 RT->System->QueueCacheNeedsUpdate(1);
444 return ( $id, $self->loc("Queue created") );
452 $self->loc('Deleting this object would break referential integrity') );
460 1 will cause this queue to no longer be available for tickets.
461 0 will re-enable this queue.
469 $RT::Handle->BeginTransaction();
470 my $set_err = $self->_Set( Field =>'Disabled', Value => $val);
472 $RT::Handle->Rollback();
473 $RT::Logger->warning("Couldn't ".($val == 1) ? "disable" : "enable"." queue ".$self->PrincipalObj->Id);
476 $self->_NewTransaction( Type => ($val == 1) ? "Disabled" : "Enabled" );
478 $RT::Handle->Commit();
480 RT->System->QueueCacheNeedsUpdate(1);
483 return (1, $self->loc("Queue disabled"));
485 return (1, $self->loc("Queue enabled"));
494 Takes either a numerical id or a textual Name and loads the specified queue.
501 my $identifier = shift;
502 if ( !$identifier ) {
506 if ( $identifier =~ /^(\d+)$/ ) {
507 $self->SUPER::LoadById($identifier);
510 $self->LoadByCols( Name => $identifier );
513 return ( $self->Id );
519 =head2 ValidateName NAME
521 Takes a queue name. Returns true if it's an ok name for
522 a new queue. Returns undef if there's already a queue by that name.
530 my ($ok, $msg) = $self->_ValidateName($name);
539 return (undef, "Queue name is required") unless length $name;
541 # Validate via the superclass first
542 # Case: short circuit if it's an integer so we don't have
543 # fale negatives when loading a temp queue
544 unless ( my $q = $self->SUPER::ValidateName($name) ) {
545 return ($q, $self->loc("'[_1]' is not a valid name.", $name));
548 my $tempqueue = RT::Queue->new(RT->SystemUser);
549 $tempqueue->Load($name);
551 #If this queue exists, return undef
552 if ( $tempqueue->Name() && $tempqueue->id != $self->id) {
553 return (undef, $self->loc("Queue already exists") );
568 return undef unless $self->CurrentUserHasRight('SeeQueue');
569 my $attr = $self->FirstAttribute('Sign') or return 0;
570 return $attr->Content;
577 return ( 0, $self->loc('Permission Denied') )
578 unless $self->CurrentUserHasRight('AdminQueue');
580 my ($status, $msg) = $self->SetAttribute(
582 Description => 'Sign outgoing messages by default',
585 return ($status, $msg) unless $status;
586 return ($status, $self->loc('Signing enabled')) if $value;
587 return ($status, $self->loc('Signing disabled'));
594 return undef unless $self->CurrentUserHasRight('SeeQueue');
595 my $attr = $self->FirstAttribute('SignAuto') or return 0;
596 return $attr->Content;
603 return ( 0, $self->loc('Permission Denied') )
604 unless $self->CurrentUserHasRight('AdminQueue');
606 my ($status, $msg) = $self->SetAttribute(
608 Description => 'Sign auto-generated outgoing messages',
611 return ($status, $msg) unless $status;
612 return ($status, $self->loc('Signing enabled')) if $value;
613 return ($status, $self->loc('Signing disabled'));
620 return undef unless $self->CurrentUserHasRight('SeeQueue');
621 my $attr = $self->FirstAttribute('Encrypt') or return 0;
622 return $attr->Content;
629 return ( 0, $self->loc('Permission Denied') )
630 unless $self->CurrentUserHasRight('AdminQueue');
632 my ($status, $msg) = $self->SetAttribute(
634 Description => 'Encrypt outgoing messages by default',
637 return ($status, $msg) unless $status;
638 return ($status, $self->loc('Encrypting enabled')) if $value;
639 return ($status, $self->loc('Encrypting disabled'));
644 Returns an RT::Templates object of all of this queue's templates.
651 my $templates = RT::Templates->new( $self->CurrentUser );
653 if ( $self->CurrentUserHasRight('ShowTemplate') ) {
654 $templates->LimitToQueue( $self->id );
663 =head2 CustomField NAME
665 Load the queue-specific custom field named NAME
672 my $cf = RT::CustomField->new($self->CurrentUser);
673 $cf->LoadByNameAndQueue(Name => $name, Queue => $self->Id);
679 =head2 TicketCustomFields
681 Returns an L<RT::CustomFields> object containing all global and
682 queue-specific B<ticket> custom fields.
686 sub TicketCustomFields {
689 my $cfs = RT::CustomFields->new( $self->CurrentUser );
690 if ( $self->CurrentUserHasRight('SeeQueue') ) {
691 $cfs->SetContextObject( $self );
692 $cfs->LimitToGlobalOrObjectId( $self->Id );
693 $cfs->LimitToLookupType( 'RT::Queue-RT::Ticket' );
694 $cfs->ApplySortOrder;
701 =head2 TicketTransactionCustomFields
703 Returns an L<RT::CustomFields> object containing all global and
704 queue-specific B<transaction> custom fields.
708 sub TicketTransactionCustomFields {
711 my $cfs = RT::CustomFields->new( $self->CurrentUser );
712 if ( $self->CurrentUserHasRight('SeeQueue') ) {
713 $cfs->SetContextObject( $self );
714 $cfs->LimitToGlobalOrObjectId( $self->Id );
715 $cfs->LimitToLookupType( 'RT::Queue-RT::Ticket-RT::Transaction' );
716 $cfs->ApplySortOrder;
725 =head2 AllRoleGroupTypes
727 Returns a list of the names of the various role group types that this queue
728 has, including Requestor and Owner. If you don't want them, see
729 L</ManageableRoleGroupTypes>.
733 sub AllRoleGroupTypes {
735 return ($self->ManageableRoleGroupTypes, qw(Requestor Owner));
738 =head2 IsRoleGroupType
740 Returns whether the passed-in type is a role group type.
744 sub IsRoleGroupType {
748 for my $valid_type ($self->AllRoleGroupTypes) {
749 return 1 if $type eq $valid_type;
755 =head2 ManageableRoleGroupTypes
757 Returns a list of the names of the various role group types that this queue
758 has, excluding Requestor and Owner. If you want them, see L</AllRoleGroupTypes>.
762 sub ManageableRoleGroupTypes {
763 return qw(Cc AdminCc);
766 =head2 IsManageableRoleGroupType
768 Returns whether the passed-in type is a manageable role group type.
772 sub IsManageableRoleGroupType {
776 for my $valid_type ($self->ManageableRoleGroupTypes) {
777 return 1 if $type eq $valid_type;
784 =head2 _CreateQueueGroups
786 Create the ticket groups and links for this ticket.
787 This routine expects to be called from Ticket->Create _inside of a transaction_
789 It will create four groups for this ticket: Requestor, Cc, AdminCc and Owner.
791 It will return true on success and undef on failure.
796 sub _CreateQueueGroups {
799 my @types = $self->AllRoleGroupTypes;
801 foreach my $type (@types) {
802 my $ok = $self->_CreateQueueRoleGroup($type);
803 return undef if !$ok;
809 sub _CreateQueueRoleGroup {
813 my $type_obj = RT::Group->new($self->CurrentUser);
814 my ($id, $msg) = $type_obj->CreateRoleGroup(Instance => $self->Id,
816 Domain => 'RT::Queue-Role');
818 $RT::Logger->error("Couldn't create a Queue group of type '$type' for queue ".
819 $self->Id.": ".$msg);
828 # _HasModifyWatcherRight {{{
829 sub _HasModifyWatcherRight {
833 PrincipalId => undef,
838 return 1 if $self->CurrentUserHasRight('ModifyQueueWatchers');
840 #If the watcher we're trying to add is for the current user
841 if ( defined $args{'PrincipalId'} && $self->CurrentUser->PrincipalId eq $args{'PrincipalId'}) {
842 if ( $args{'Type'} eq 'AdminCc' ) {
843 return 1 if $self->CurrentUserHasRight('WatchAsAdminCc');
845 elsif ( $args{'Type'} eq 'Cc' or $args{'Type'} eq 'Requestor' ) {
846 return 1 if $self->CurrentUserHasRight('Watch');
849 $RT::Logger->warning( "$self -> _HasModifyWatcher got passed a bogus type $args{Type}");
850 return ( 0, $self->loc('Invalid queue role group type [_1]', $args{Type}) );
854 return ( 0, $self->loc("Permission Denied") );
860 AddWatcher takes a parameter hash. The keys are as follows:
862 Type One of Requestor, Cc, AdminCc
864 PrinicpalId The RT::Principal id of the user or group that's being added as a watcher
865 Email The email address of the new watcher. If a user with this
866 email address can't be found, a new nonprivileged user will be created.
868 If the watcher you're trying to set has an RT account, set the Owner parameter to their User Id. Otherwise, set the Email parameter to their Email address.
870 Returns a tuple of (status/id, message).
878 PrincipalId => undef,
883 return ( 0, "No principal specified" )
884 unless $args{'Email'} or $args{'PrincipalId'};
886 if ( !$args{'PrincipalId'} && $args{'Email'} ) {
887 my $user = RT::User->new( $self->CurrentUser );
888 $user->LoadByEmail( $args{'Email'} );
889 $args{'PrincipalId'} = $user->PrincipalId if $user->id;
892 return ( 0, "Unknown watcher type [_1]", $args{Type} )
893 unless $self->IsRoleGroupType($args{Type});
895 my ($ok, $msg) = $self->_HasModifyWatcherRight(%args);
896 return ($ok, $msg) if !$ok;
898 return $self->_AddWatcher(%args);
901 #This contains the meat of AddWatcher. but can be called from a routine like
902 # Create, which doesn't need the additional acl check
908 PrincipalId => undef,
914 my $principal = RT::Principal->new( $self->CurrentUser );
915 if ( $args{'PrincipalId'} ) {
916 $principal->Load( $args{'PrincipalId'} );
917 if ( $principal->id and $principal->IsUser and my $email = $principal->Object->EmailAddress ) {
918 return (0, $self->loc("[_1] is an address RT receives mail at. Adding it as a '[_2]' would create a mail loop", $email, $self->loc($args{'Type'})))
919 if RT::EmailParser->IsRTAddress( $email );
922 elsif ( $args{'Email'} ) {
923 if ( RT::EmailParser->IsRTAddress( $args{'Email'} ) ) {
924 return (0, $self->loc("[_1] is an address RT receives mail at. Adding it as a '[_2]' would create a mail loop", $args{'Email'}, $self->loc($args{'Type'})));
926 my $user = RT::User->new($self->CurrentUser);
927 $user->LoadByEmail( $args{'Email'} );
928 $user->Load( $args{'Email'} )
931 if ( $user->Id ) { # If the user exists
932 $principal->Load( $user->PrincipalId );
934 # if the user doesn't exist, we need to create a new user
935 my $new_user = RT::User->new(RT->SystemUser);
937 my ( $Address, $Name ) =
938 RT::Interface::Email::ParseAddressFromHeader($args{'Email'});
940 my ( $Val, $Message ) = $new_user->Create(
942 EmailAddress => $Address,
945 Comments => 'Autocreated when added as a watcher'
948 $RT::Logger->error("Failed to create user ".$args{'Email'} .": " .$Message);
949 # Deal with the race condition of two account creations at once
950 $new_user->LoadByEmail( $args{'Email'} );
952 $principal->Load( $new_user->PrincipalId );
955 # If we can't find this watcher, we need to bail.
956 unless ( $principal->Id ) {
957 return(0, $self->loc("Could not find or create that user"));
960 my $group = RT::Group->new($self->CurrentUser);
961 $group->LoadQueueRoleGroup(Type => $args{'Type'}, Queue => $self->Id);
962 unless ($group->id) {
963 return(0,$self->loc("Group not found"));
966 if ( $group->HasMember( $principal)) {
968 return ( 0, $self->loc('[_1] is already a [_2] for this queue',
969 $principal->Object->Name, $args{'Type'}) );
973 my ($m_id, $m_msg) = $group->_AddMember(PrincipalId => $principal->Id);
975 $RT::Logger->error("Failed to add ".$principal->Id." as a member of group ".$group->Id.": ".$m_msg);
977 return ( 0, $self->loc('Could not make [_1] a [_2] for this queue',
978 $principal->Object->Name, $args{'Type'}) );
980 return ( 1, $self->loc("Added [_1] to members of [_2] for this queue.", $principal->Object->Name, $args{'Type'} ));
985 =head2 DeleteWatcher { Type => TYPE, PrincipalId => PRINCIPAL_ID, Email => EMAIL_ADDRESS }
988 Deletes a queue watcher. Takes two arguments:
990 Type (one of Requestor,Cc,AdminCc)
994 PrincipalId (an RT::Principal Id of the watcher you want to remove)
996 Email (the email address of an existing wathcer)
1005 my %args = ( Type => undef,
1006 PrincipalId => undef,
1010 unless ( $args{'PrincipalId'} || $args{'Email'} ) {
1011 return ( 0, $self->loc("No principal specified") );
1014 if ( !$args{PrincipalId} and $args{Email} ) {
1015 my $user = RT::User->new( $self->CurrentUser );
1016 my ($rv, $msg) = $user->LoadByEmail( $args{Email} );
1017 $args{PrincipalId} = $user->PrincipalId if $rv;
1020 my $principal = RT::Principal->new( $self->CurrentUser );
1021 if ( $args{'PrincipalId'} ) {
1022 $principal->Load( $args{'PrincipalId'} );
1025 my $user = RT::User->new( $self->CurrentUser );
1026 $user->LoadByEmail( $args{'Email'} );
1027 $principal->Load( $user->Id );
1030 # If we can't find this watcher, we need to bail.
1031 unless ( $principal->Id ) {
1032 return ( 0, $self->loc("Could not find that principal") );
1035 my $group = RT::Group->new($self->CurrentUser);
1036 $group->LoadQueueRoleGroup(Type => $args{'Type'}, Queue => $self->Id);
1037 unless ($group->id) {
1038 return(0,$self->loc("Group not found"));
1041 return ( 0, $self->loc('Unknown watcher type [_1]', $args{Type}) )
1042 unless $self->IsRoleGroupType($args{Type});
1044 my ($ok, $msg) = $self->_HasModifyWatcherRight(%args);
1045 return ($ok, $msg) if !$ok;
1047 # see if this user is already a watcher.
1049 unless ( $group->HasMember($principal)) {
1050 return ( 0, $self->loc('[_1] is not a [_2] for this queue',
1051 $principal->Object->Name, $args{'Type'}) );
1054 my ($m_id, $m_msg) = $group->_DeleteMember($principal->Id);
1056 $RT::Logger->error("Failed to delete ".$principal->Id.
1057 " as a member of group ".$group->Id.": ".$m_msg);
1059 return ( 0, $self->loc('Could not remove [_1] as a [_2] for this queue',
1060 $principal->Object->Name, $args{'Type'}) );
1063 return ( 1, $self->loc("Removed [_1] from members of [_2] for this queue.", $principal->Object->Name, $args{'Type'} ));
1068 =head2 AdminCcAddresses
1070 returns String: All queue AdminCc email addresses as a string
1074 sub AdminCcAddresses {
1077 unless ( $self->CurrentUserHasRight('SeeQueue') ) {
1081 return ( $self->AdminCc->MemberEmailAddressesAsString )
1089 returns String: All queue Ccs as a string of email addresses
1096 unless ( $self->CurrentUserHasRight('SeeQueue') ) {
1100 return ( $self->Cc->MemberEmailAddressesAsString);
1109 Returns an RT::Group object which contains this Queue's Ccs.
1110 If the user doesn't have "ShowQueue" permission, returns an empty group
1117 my $group = RT::Group->new($self->CurrentUser);
1118 if ( $self->CurrentUserHasRight('SeeQueue') ) {
1119 $group->LoadQueueRoleGroup(Type => 'Cc', Queue => $self->Id);
1130 Returns an RT::Group object which contains this Queue's AdminCcs.
1131 If the user doesn't have "ShowQueue" permission, returns an empty group
1138 my $group = RT::Group->new($self->CurrentUser);
1139 if ( $self->CurrentUserHasRight('SeeQueue') ) {
1140 $group->LoadQueueRoleGroup(Type => 'AdminCc', Queue => $self->Id);
1148 # a generic routine to be called by IsRequestor, IsCc and IsAdminCc
1150 =head2 IsWatcher { Type => TYPE, PrincipalId => PRINCIPAL_ID }
1152 Takes a param hash with the attributes Type and PrincipalId
1154 Type is one of Requestor, Cc, AdminCc and Owner
1156 PrincipalId is an RT::Principal id
1158 Returns true if that principal is a member of the group Type for this queue
1166 my %args = ( Type => 'Cc',
1167 PrincipalId => undef,
1171 # Load the relevant group.
1172 my $group = RT::Group->new($self->CurrentUser);
1173 $group->LoadQueueRoleGroup(Type => $args{'Type'}, Queue => $self->id);
1174 # Ask if it has the member in question
1176 my $principal = RT::Principal->new($self->CurrentUser);
1177 $principal->Load($args{'PrincipalId'});
1178 unless ($principal->Id) {
1182 return ($group->HasMemberRecursively($principal));
1188 =head2 IsCc PRINCIPAL_ID
1190 Takes an RT::Principal id.
1191 Returns true if the principal is a requestor of the current queue.
1200 return ( $self->IsWatcher( Type => 'Cc', PrincipalId => $cc ) );
1206 =head2 IsAdminCc PRINCIPAL_ID
1208 Takes an RT::Principal id.
1209 Returns true if the principal is a requestor of the current queue.
1217 return ( $self->IsWatcher( Type => 'AdminCc', PrincipalId => $person ) );
1233 unless ( $self->CurrentUserHasRight('AdminQueue') ) {
1234 return ( 0, $self->loc('Permission Denied') );
1236 RT->System->QueueCacheNeedsUpdate(1);
1237 return ( $self->SUPER::_Set(@_) );
1245 unless ( $self->CurrentUserHasRight('SeeQueue') ) {
1249 return ( $self->__Value(@_) );
1254 =head2 CurrentUserHasRight
1256 Takes one argument. A textual string with the name of the right we want to check.
1257 Returns true if the current user has that right for this queue.
1258 Returns undef otherwise.
1262 sub CurrentUserHasRight {
1268 Principal => $self->CurrentUser,
1275 =head2 CurrentUserCanSee
1277 Returns true if the current user can see the queue, using SeeQueue
1281 sub CurrentUserCanSee {
1284 return $self->CurrentUserHasRight('SeeQueue');
1290 Takes a param hash with the fields 'Right' and 'Principal'.
1291 Principal defaults to the current user.
1292 Returns true if the principal has that right for this queue.
1293 Returns undef otherwise.
1297 # TAKES: Right and optional "Principal" which defaults to the current user
1302 Principal => $self->CurrentUser,
1305 my $principal = delete $args{'Principal'};
1306 unless ( $principal ) {
1307 $RT::Logger->error("Principal undefined in Queue::HasRight");
1311 return $principal->HasRight(
1313 Object => ($self->Id ? $self : $RT::System),
1322 Returns the current value of id.
1323 (In the database, id is stored as int(11).)
1331 Returns the current value of Name.
1332 (In the database, Name is stored as varchar(200).)
1336 =head2 SetName VALUE
1340 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1341 (In the database, Name will be stored as a varchar(200).)
1349 Returns the current value of Description.
1350 (In the database, Description is stored as varchar(255).)
1354 =head2 SetDescription VALUE
1357 Set Description to VALUE.
1358 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1359 (In the database, Description will be stored as a varchar(255).)
1365 =head2 CorrespondAddress
1367 Returns the current value of CorrespondAddress.
1368 (In the database, CorrespondAddress is stored as varchar(120).)
1372 =head2 SetCorrespondAddress VALUE
1375 Set CorrespondAddress to VALUE.
1376 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1377 (In the database, CorrespondAddress will be stored as a varchar(120).)
1383 =head2 CommentAddress
1385 Returns the current value of CommentAddress.
1386 (In the database, CommentAddress is stored as varchar(120).)
1390 =head2 SetCommentAddress VALUE
1393 Set CommentAddress to VALUE.
1394 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1395 (In the database, CommentAddress will be stored as a varchar(120).)
1403 Returns the current value of Lifecycle.
1404 (In the database, Lifecycle is stored as varchar(32).)
1408 =head2 SetLifecycle VALUE
1411 Set Lifecycle to VALUE.
1412 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1413 (In the database, Lifecycle will be stored as a varchar(32).)
1420 Returns the current value of SubjectTag.
1421 (In the database, SubjectTag is stored as varchar(120).)
1425 =head2 SetSubjectTag VALUE
1428 Set SubjectTag to VALUE.
1429 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1430 (In the database, SubjectTag will be stored as a varchar(120).)
1436 =head2 InitialPriority
1438 Returns the current value of InitialPriority.
1439 (In the database, InitialPriority is stored as int(11).)
1443 =head2 SetInitialPriority VALUE
1446 Set InitialPriority to VALUE.
1447 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1448 (In the database, InitialPriority will be stored as a int(11).)
1454 =head2 FinalPriority
1456 Returns the current value of FinalPriority.
1457 (In the database, FinalPriority is stored as int(11).)
1461 =head2 SetFinalPriority VALUE
1464 Set FinalPriority to VALUE.
1465 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1466 (In the database, FinalPriority will be stored as a int(11).)
1474 Returns the current value of DefaultDueIn.
1475 (In the database, DefaultDueIn is stored as int(11).)
1479 =head2 SetDefaultDueIn VALUE
1482 Set DefaultDueIn to VALUE.
1483 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1484 (In the database, DefaultDueIn will be stored as a int(11).)
1492 Returns the current value of Creator.
1493 (In the database, Creator is stored as int(11).)
1501 Returns the current value of Created.
1502 (In the database, Created is stored as datetime.)
1508 =head2 LastUpdatedBy
1510 Returns the current value of LastUpdatedBy.
1511 (In the database, LastUpdatedBy is stored as int(11).)
1519 Returns the current value of LastUpdated.
1520 (In the database, LastUpdated is stored as datetime.)
1528 Returns the current value of Disabled.
1529 (In the database, Disabled is stored as smallint(6).)
1533 =head2 SetDisabled VALUE
1536 Set Disabled to VALUE.
1537 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1538 (In the database, Disabled will be stored as a smallint(6).)
1545 sub _CoreAccessible {
1549 {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''},
1551 {read => 1, write => 1, sql_type => 12, length => 200, is_blob => 0, is_numeric => 0, type => 'varchar(200)', default => ''},
1553 {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''},
1554 CorrespondAddress =>
1555 {read => 1, write => 1, sql_type => 12, length => 120, is_blob => 0, is_numeric => 0, type => 'varchar(120)', default => ''},
1557 {read => 1, write => 1, sql_type => 12, length => 120, is_blob => 0, is_numeric => 0, type => 'varchar(120)', default => ''},
1559 {read => 1, write => 1, sql_type => 12, length => 120, is_blob => 0, is_numeric => 0, type => 'varchar(120)', default => ''},
1561 {read => 1, write => 1, sql_type => 12, length => 32, is_blob => 0, is_numeric => 0, type => 'varchar(32)', default => 'default'},
1563 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
1565 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
1567 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
1569 {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
1571 {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''},
1573 {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
1575 {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''},
1577 {read => 1, write => 1, sql_type => 5, length => 6, is_blob => 0, is_numeric => 1, type => 'smallint(6)', default => '0'},
1584 RT::Base->_ImportOverlays();