1 # BEGIN BPS TAGGED BLOCK {{{
5 # This software is Copyright (c) 1996-2012 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');
268 if ( $value && $value ne 'default' ) {
269 return (0, $self->loc('[_1] is not valid lifecycle', $value ))
270 unless $self->ValidateLifecycle( $value );
275 return $self->_Set( Field => 'Lifecycle', Value => $value, @_ );
278 =head2 ValidateLifecycle NAME
280 Takes a lifecycle name. Returns true if it's an ok name and such
281 lifecycle is configured. Returns undef otherwise.
285 sub ValidateLifecycle {
288 return undef unless RT::Lifecycle->Load( $value );
293 =head2 ActiveStatusArray
295 Returns an array of all ActiveStatuses for this queue
299 sub ActiveStatusArray {
301 return $self->Lifecycle->Valid('initial', 'active');
304 =head2 InactiveStatusArray
306 Returns an array of all InactiveStatuses for this queue
310 sub InactiveStatusArray {
312 return $self->Lifecycle->Inactive;
317 Returns an array of all statuses for this queue
323 return $self->Lifecycle->Valid( @_ );
326 =head2 IsValidStatus value
328 Returns true if value is a valid status. Otherwise, returns 0.
334 return $self->Lifecycle->IsValid( shift );
337 =head2 IsActiveStatus value
339 Returns true if value is a Active status. Otherwise, returns 0
345 return $self->Lifecycle->IsValid( shift, 'initial', 'active');
350 =head2 IsInactiveStatus value
352 Returns true if value is a Inactive status. Otherwise, returns 0
357 sub IsInactiveStatus {
359 return $self->Lifecycle->IsInactive( shift );
369 Arguments: ARGS is a hash of named parameters. Valid parameters are:
379 If you pass the ACL check, it creates the queue and returns its queue id.
389 CorrespondAddress => '',
390 CommentAddress => '',
391 Lifecycle => 'default',
393 InitialPriority => 0,
398 _RecordTransaction => 1,
402 unless ( $self->CurrentUser->HasRight(Right => 'AdminQueue', Object => $RT::System) )
404 return ( 0, $self->loc("No permission to create queues") );
408 my ($val, $msg) = $self->_ValidateName( $args{'Name'} );
409 return ($val, $msg) unless $val;
412 if ( $args{'Lifecycle'} && $args{'Lifecycle'} ne 'default' ) {
413 return ( 0, $self->loc('Invalid lifecycle name') )
414 unless $self->ValidateLifecycle( $args{'Lifecycle'} );
416 $args{'Lifecycle'} = undef;
419 my %attrs = map {$_ => 1} $self->ReadableAttributes;
421 #TODO better input validation
422 $RT::Handle->BeginTransaction();
423 my $id = $self->SUPER::Create( map { $_ => $args{$_} } grep exists $args{$_}, keys %attrs );
425 $RT::Handle->Rollback();
426 return ( 0, $self->loc('Queue could not be created') );
429 my $create_ret = $self->_CreateQueueGroups();
430 unless ($create_ret) {
431 $RT::Handle->Rollback();
432 return ( 0, $self->loc('Queue could not be created') );
434 if ( $args{'_RecordTransaction'} ) {
435 $self->_NewTransaction( Type => "Create" );
439 if ( defined $args{'Sign'} ) {
440 my ($status, $msg) = $self->SetSign( $args{'Sign'} );
441 $RT::Logger->error("Couldn't set attribute 'Sign': $msg")
444 if ( defined $args{'Encrypt'} ) {
445 my ($status, $msg) = $self->SetEncrypt( $args{'Encrypt'} );
446 $RT::Logger->error("Couldn't set attribute 'Encrypt': $msg")
450 RT->System->QueueCacheNeedsUpdate(1);
452 return ( $id, $self->loc("Queue created") );
460 $self->loc('Deleting this object would break referential integrity') );
468 1 will cause this queue to no longer be available for tickets.
469 0 will re-enable this queue.
477 $RT::Handle->BeginTransaction();
478 my $set_err = $self->_Set( Field =>'Disabled', Value => $val);
480 $RT::Handle->Rollback();
481 $RT::Logger->warning("Couldn't ".($val == 1) ? "disable" : "enable"." queue ".$self->PrincipalObj->Id);
484 $self->_NewTransaction( Type => ($val == 1) ? "Disabled" : "Enabled" );
486 $RT::Handle->Commit();
488 RT->System->QueueCacheNeedsUpdate(1);
491 return (1, $self->loc("Queue disabled"));
493 return (1, $self->loc("Queue enabled"));
502 Takes either a numerical id or a textual Name and loads the specified queue.
509 my $identifier = shift;
510 if ( !$identifier ) {
514 if ( $identifier =~ /^(\d+)$/ ) {
515 $self->SUPER::LoadById($identifier);
518 $self->LoadByCols( Name => $identifier );
521 return ( $self->Id );
527 =head2 ValidateName NAME
529 Takes a queue name. Returns true if it's an ok name for
530 a new queue. Returns undef if there's already a queue by that name.
538 my ($ok, $msg) = $self->_ValidateName($name);
547 return (undef, "Queue name is required") unless length $name;
549 # Validate via the superclass first
550 # Case: short circuit if it's an integer so we don't have
551 # fale negatives when loading a temp queue
552 unless ( my $q = $self->SUPER::ValidateName($name) ) {
553 return ($q, $self->loc("'[_1]' is not a valid name.", $name));
556 my $tempqueue = RT::Queue->new(RT->SystemUser);
557 $tempqueue->Load($name);
559 #If this queue exists, return undef
560 if ( $tempqueue->Name() && $tempqueue->id != $self->id) {
561 return (undef, $self->loc("Queue already exists") );
576 return undef unless $self->CurrentUserHasRight('SeeQueue');
577 my $attr = $self->FirstAttribute('Sign') or return 0;
578 return $attr->Content;
585 return ( 0, $self->loc('Permission Denied') )
586 unless $self->CurrentUserHasRight('AdminQueue');
588 my ($status, $msg) = $self->SetAttribute(
590 Description => 'Sign outgoing messages by default',
593 return ($status, $msg) unless $status;
594 return ($status, $self->loc('Signing enabled')) if $value;
595 return ($status, $self->loc('Signing disabled'));
602 return undef unless $self->CurrentUserHasRight('SeeQueue');
603 my $attr = $self->FirstAttribute('Encrypt') or return 0;
604 return $attr->Content;
611 return ( 0, $self->loc('Permission Denied') )
612 unless $self->CurrentUserHasRight('AdminQueue');
614 my ($status, $msg) = $self->SetAttribute(
616 Description => 'Encrypt outgoing messages by default',
619 return ($status, $msg) unless $status;
620 return ($status, $self->loc('Encrypting enabled')) if $value;
621 return ($status, $self->loc('Encrypting disabled'));
626 Returns an RT::Templates object of all of this queue's templates.
633 my $templates = RT::Templates->new( $self->CurrentUser );
635 if ( $self->CurrentUserHasRight('ShowTemplate') ) {
636 $templates->LimitToQueue( $self->id );
645 =head2 CustomField NAME
647 Load the queue-specific custom field named NAME
654 my $cf = RT::CustomField->new($self->CurrentUser);
655 $cf->LoadByNameAndQueue(Name => $name, Queue => $self->Id);
661 =head2 TicketCustomFields
663 Returns an L<RT::CustomFields> object containing all global and
664 queue-specific B<ticket> custom fields.
668 sub TicketCustomFields {
671 my $cfs = RT::CustomFields->new( $self->CurrentUser );
672 if ( $self->CurrentUserHasRight('SeeQueue') ) {
673 $cfs->SetContextObject( $self );
674 $cfs->LimitToGlobalOrObjectId( $self->Id );
675 $cfs->LimitToLookupType( 'RT::Queue-RT::Ticket' );
676 $cfs->ApplySortOrder;
683 =head2 TicketTransactionCustomFields
685 Returns an L<RT::CustomFields> object containing all global and
686 queue-specific B<transaction> custom fields.
690 sub TicketTransactionCustomFields {
693 my $cfs = RT::CustomFields->new( $self->CurrentUser );
694 if ( $self->CurrentUserHasRight('SeeQueue') ) {
695 $cfs->SetContextObject( $self );
696 $cfs->LimitToGlobalOrObjectId( $self->Id );
697 $cfs->LimitToLookupType( 'RT::Queue-RT::Ticket-RT::Transaction' );
698 $cfs->ApplySortOrder;
707 =head2 AllRoleGroupTypes
709 Returns a list of the names of the various role group types that this queue
710 has, including Requestor and Owner. If you don't want them, see
711 L</ManageableRoleGroupTypes>.
715 sub AllRoleGroupTypes {
717 return ($self->ManageableRoleGroupTypes, qw(Requestor Owner));
720 =head2 IsRoleGroupType
722 Returns whether the passed-in type is a role group type.
726 sub IsRoleGroupType {
730 for my $valid_type ($self->AllRoleGroupTypes) {
731 return 1 if $type eq $valid_type;
737 =head2 ManageableRoleGroupTypes
739 Returns a list of the names of the various role group types that this queue
740 has, excluding Requestor and Owner. If you want them, see L</AllRoleGroupTypes>.
744 sub ManageableRoleGroupTypes {
745 return qw(Cc AdminCc);
748 =head2 IsManageableRoleGroupType
750 Returns whether the passed-in type is a manageable role group type.
754 sub IsManageableRoleGroupType {
758 for my $valid_type ($self->ManageableRoleGroupTypes) {
759 return 1 if $type eq $valid_type;
766 =head2 _CreateQueueGroups
768 Create the ticket groups and links for this ticket.
769 This routine expects to be called from Ticket->Create _inside of a transaction_
771 It will create four groups for this ticket: Requestor, Cc, AdminCc and Owner.
773 It will return true on success and undef on failure.
778 sub _CreateQueueGroups {
781 my @types = $self->AllRoleGroupTypes;
783 foreach my $type (@types) {
784 my $ok = $self->_CreateQueueRoleGroup($type);
785 return undef if !$ok;
791 sub _CreateQueueRoleGroup {
795 my $type_obj = RT::Group->new($self->CurrentUser);
796 my ($id, $msg) = $type_obj->CreateRoleGroup(Instance => $self->Id,
798 Domain => 'RT::Queue-Role');
800 $RT::Logger->error("Couldn't create a Queue group of type '$type' for queue ".
801 $self->Id.": ".$msg);
810 # _HasModifyWatcherRight {{{
811 sub _HasModifyWatcherRight {
815 PrincipalId => undef,
820 return 1 if $self->CurrentUserHasRight('ModifyQueueWatchers');
822 #If the watcher we're trying to add is for the current user
823 if ( defined $args{'PrincipalId'} && $self->CurrentUser->PrincipalId eq $args{'PrincipalId'}) {
824 if ( $args{'Type'} eq 'AdminCc' ) {
825 return 1 if $self->CurrentUserHasRight('WatchAsAdminCc');
827 elsif ( $args{'Type'} eq 'Cc' or $args{'Type'} eq 'Requestor' ) {
828 return 1 if $self->CurrentUserHasRight('Watch');
831 $RT::Logger->warning( "$self -> _HasModifyWatcher got passed a bogus type $args{Type}");
832 return ( 0, $self->loc('Invalid queue role group type [_1]', $args{Type}) );
836 return ( 0, $self->loc("Permission Denied") );
842 AddWatcher takes a parameter hash. The keys are as follows:
844 Type One of Requestor, Cc, AdminCc
846 PrinicpalId The RT::Principal id of the user or group that's being added as a watcher
847 Email The email address of the new watcher. If a user with this
848 email address can't be found, a new nonprivileged user will be created.
850 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.
852 Returns a tuple of (status/id, message).
860 PrincipalId => undef,
865 return ( 0, "No principal specified" )
866 unless $args{'Email'} or $args{'PrincipalId'};
868 if ( !$args{'PrincipalId'} && $args{'Email'} ) {
869 my $user = RT::User->new( $self->CurrentUser );
870 $user->LoadByEmail( $args{'Email'} );
871 $args{'PrincipalId'} = $user->PrincipalId if $user->id;
874 return ( 0, "Unknown watcher type [_1]", $args{Type} )
875 unless $self->IsRoleGroupType($args{Type});
877 my ($ok, $msg) = $self->_HasModifyWatcherRight(%args);
878 return ($ok, $msg) if !$ok;
880 return $self->_AddWatcher(%args);
883 #This contains the meat of AddWatcher. but can be called from a routine like
884 # Create, which doesn't need the additional acl check
890 PrincipalId => undef,
896 my $principal = RT::Principal->new( $self->CurrentUser );
897 if ( $args{'PrincipalId'} ) {
898 $principal->Load( $args{'PrincipalId'} );
899 if ( $principal->id and $principal->IsUser and my $email = $principal->Object->EmailAddress ) {
900 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'})))
901 if RT::EmailParser->IsRTAddress( $email );
904 elsif ( $args{'Email'} ) {
905 if ( RT::EmailParser->IsRTAddress( $args{'Email'} ) ) {
906 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'})));
908 my $user = RT::User->new($self->CurrentUser);
909 $user->LoadByEmail( $args{'Email'} );
910 $user->Load( $args{'Email'} )
913 if ( $user->Id ) { # If the user exists
914 $principal->Load( $user->PrincipalId );
916 # if the user doesn't exist, we need to create a new user
917 my $new_user = RT::User->new(RT->SystemUser);
919 my ( $Address, $Name ) =
920 RT::Interface::Email::ParseAddressFromHeader($args{'Email'});
922 my ( $Val, $Message ) = $new_user->Create(
924 EmailAddress => $Address,
927 Comments => 'Autocreated when added as a watcher'
930 $RT::Logger->error("Failed to create user ".$args{'Email'} .": " .$Message);
931 # Deal with the race condition of two account creations at once
932 $new_user->LoadByEmail( $args{'Email'} );
934 $principal->Load( $new_user->PrincipalId );
937 # If we can't find this watcher, we need to bail.
938 unless ( $principal->Id ) {
939 return(0, $self->loc("Could not find or create that user"));
942 my $group = RT::Group->new($self->CurrentUser);
943 $group->LoadQueueRoleGroup(Type => $args{'Type'}, Queue => $self->Id);
944 unless ($group->id) {
945 return(0,$self->loc("Group not found"));
948 if ( $group->HasMember( $principal)) {
950 return ( 0, $self->loc('That principal is already a [_1] for this queue', $args{'Type'}) );
954 my ($m_id, $m_msg) = $group->_AddMember(PrincipalId => $principal->Id);
956 $RT::Logger->error("Failed to add ".$principal->Id." as a member of group ".$group->Id.": ".$m_msg);
958 return ( 0, $self->loc('Could not make that principal a [_1] for this queue', $args{'Type'}) );
960 return ( 1, $self->loc("Added [_1] to members of [_2] for this queue.", $principal->Object->Name, $args{'Type'} ));
965 =head2 DeleteWatcher { Type => TYPE, PrincipalId => PRINCIPAL_ID, Email => EMAIL_ADDRESS }
968 Deletes a queue watcher. Takes two arguments:
970 Type (one of Requestor,Cc,AdminCc)
974 PrincipalId (an RT::Principal Id of the watcher you want to remove)
976 Email (the email address of an existing wathcer)
985 my %args = ( Type => undef,
986 PrincipalId => undef,
990 unless ( $args{'PrincipalId'} || $args{'Email'} ) {
991 return ( 0, $self->loc("No principal specified") );
994 if ( !$args{PrincipalId} and $args{Email} ) {
995 my $user = RT::User->new( $self->CurrentUser );
996 my ($rv, $msg) = $user->LoadByEmail( $args{Email} );
997 $args{PrincipalId} = $user->PrincipalId if $rv;
1000 my $principal = RT::Principal->new( $self->CurrentUser );
1001 if ( $args{'PrincipalId'} ) {
1002 $principal->Load( $args{'PrincipalId'} );
1005 my $user = RT::User->new( $self->CurrentUser );
1006 $user->LoadByEmail( $args{'Email'} );
1007 $principal->Load( $user->Id );
1010 # If we can't find this watcher, we need to bail.
1011 unless ( $principal->Id ) {
1012 return ( 0, $self->loc("Could not find that principal") );
1015 my $group = RT::Group->new($self->CurrentUser);
1016 $group->LoadQueueRoleGroup(Type => $args{'Type'}, Queue => $self->Id);
1017 unless ($group->id) {
1018 return(0,$self->loc("Group not found"));
1021 return ( 0, $self->loc('Unknown watcher type [_1]', $args{Type}) )
1022 unless $self->IsRoleGroupType($args{Type});
1024 my ($ok, $msg) = $self->_HasModifyWatcherRight(%args);
1025 return ($ok, $msg) if !$ok;
1027 # see if this user is already a watcher.
1029 unless ( $group->HasMember($principal)) {
1031 $self->loc('That principal is not a [_1] for this queue', $args{'Type'}) );
1034 my ($m_id, $m_msg) = $group->_DeleteMember($principal->Id);
1036 $RT::Logger->error("Failed to delete ".$principal->Id.
1037 " as a member of group ".$group->Id.": ".$m_msg);
1039 return ( 0, $self->loc('Could not remove that principal as a [_1] for this queue', $args{'Type'}) );
1042 return ( 1, $self->loc("Removed [_1] from members of [_2] for this queue.", $principal->Object->Name, $args{'Type'} ));
1047 =head2 AdminCcAddresses
1049 returns String: All queue AdminCc email addresses as a string
1053 sub AdminCcAddresses {
1056 unless ( $self->CurrentUserHasRight('SeeQueue') ) {
1060 return ( $self->AdminCc->MemberEmailAddressesAsString )
1068 returns String: All queue Ccs as a string of email addresses
1075 unless ( $self->CurrentUserHasRight('SeeQueue') ) {
1079 return ( $self->Cc->MemberEmailAddressesAsString);
1088 Returns an RT::Group object which contains this Queue's Ccs.
1089 If the user doesn't have "ShowQueue" permission, returns an empty group
1096 my $group = RT::Group->new($self->CurrentUser);
1097 if ( $self->CurrentUserHasRight('SeeQueue') ) {
1098 $group->LoadQueueRoleGroup(Type => 'Cc', Queue => $self->Id);
1109 Returns an RT::Group object which contains this Queue's AdminCcs.
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 => 'AdminCc', Queue => $self->Id);
1127 # a generic routine to be called by IsRequestor, IsCc and IsAdminCc
1129 =head2 IsWatcher { Type => TYPE, PrincipalId => PRINCIPAL_ID }
1131 Takes a param hash with the attributes Type and PrincipalId
1133 Type is one of Requestor, Cc, AdminCc and Owner
1135 PrincipalId is an RT::Principal id
1137 Returns true if that principal is a member of the group Type for this queue
1145 my %args = ( Type => 'Cc',
1146 PrincipalId => undef,
1150 # Load the relevant group.
1151 my $group = RT::Group->new($self->CurrentUser);
1152 $group->LoadQueueRoleGroup(Type => $args{'Type'}, Queue => $self->id);
1153 # Ask if it has the member in question
1155 my $principal = RT::Principal->new($self->CurrentUser);
1156 $principal->Load($args{'PrincipalId'});
1157 unless ($principal->Id) {
1161 return ($group->HasMemberRecursively($principal));
1167 =head2 IsCc PRINCIPAL_ID
1169 Takes an RT::Principal id.
1170 Returns true if the principal is a requestor of the current queue.
1179 return ( $self->IsWatcher( Type => 'Cc', PrincipalId => $cc ) );
1185 =head2 IsAdminCc PRINCIPAL_ID
1187 Takes an RT::Principal id.
1188 Returns true if the principal is a requestor of the current queue.
1196 return ( $self->IsWatcher( Type => 'AdminCc', PrincipalId => $person ) );
1212 unless ( $self->CurrentUserHasRight('AdminQueue') ) {
1213 return ( 0, $self->loc('Permission Denied') );
1215 return ( $self->SUPER::_Set(@_) );
1223 unless ( $self->CurrentUserHasRight('SeeQueue') ) {
1227 return ( $self->__Value(@_) );
1232 =head2 CurrentUserHasRight
1234 Takes one argument. A textual string with the name of the right we want to check.
1235 Returns true if the current user has that right for this queue.
1236 Returns undef otherwise.
1240 sub CurrentUserHasRight {
1246 Principal => $self->CurrentUser,
1253 =head2 CurrentUserCanSee
1255 Returns true if the current user can see the queue, using SeeQueue
1259 sub CurrentUserCanSee {
1262 return $self->CurrentUserHasRight('SeeQueue');
1268 Takes a param hash with the fields 'Right' and 'Principal'.
1269 Principal defaults to the current user.
1270 Returns true if the principal has that right for this queue.
1271 Returns undef otherwise.
1275 # TAKES: Right and optional "Principal" which defaults to the current user
1280 Principal => $self->CurrentUser,
1283 my $principal = delete $args{'Principal'};
1284 unless ( $principal ) {
1285 $RT::Logger->error("Principal undefined in Queue::HasRight");
1289 return $principal->HasRight(
1291 Object => ($self->Id ? $self : $RT::System),
1300 Returns the current value of id.
1301 (In the database, id is stored as int(11).)
1309 Returns the current value of Name.
1310 (In the database, Name is stored as varchar(200).)
1314 =head2 SetName VALUE
1318 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1319 (In the database, Name will be stored as a varchar(200).)
1327 Returns the current value of Description.
1328 (In the database, Description is stored as varchar(255).)
1332 =head2 SetDescription VALUE
1335 Set Description to VALUE.
1336 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1337 (In the database, Description will be stored as a varchar(255).)
1343 =head2 CorrespondAddress
1345 Returns the current value of CorrespondAddress.
1346 (In the database, CorrespondAddress is stored as varchar(120).)
1350 =head2 SetCorrespondAddress VALUE
1353 Set CorrespondAddress to VALUE.
1354 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1355 (In the database, CorrespondAddress will be stored as a varchar(120).)
1361 =head2 CommentAddress
1363 Returns the current value of CommentAddress.
1364 (In the database, CommentAddress is stored as varchar(120).)
1368 =head2 SetCommentAddress VALUE
1371 Set CommentAddress to VALUE.
1372 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1373 (In the database, CommentAddress will be stored as a varchar(120).)
1381 Returns the current value of Lifecycle.
1382 (In the database, Lifecycle is stored as varchar(32).)
1386 =head2 SetLifecycle VALUE
1389 Set Lifecycle to VALUE.
1390 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1391 (In the database, Lifecycle will be stored as a varchar(32).)
1398 Returns the current value of SubjectTag.
1399 (In the database, SubjectTag is stored as varchar(120).)
1403 =head2 SetSubjectTag VALUE
1406 Set SubjectTag to VALUE.
1407 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1408 (In the database, SubjectTag will be stored as a varchar(120).)
1414 =head2 InitialPriority
1416 Returns the current value of InitialPriority.
1417 (In the database, InitialPriority is stored as int(11).)
1421 =head2 SetInitialPriority VALUE
1424 Set InitialPriority to VALUE.
1425 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1426 (In the database, InitialPriority will be stored as a int(11).)
1432 =head2 FinalPriority
1434 Returns the current value of FinalPriority.
1435 (In the database, FinalPriority is stored as int(11).)
1439 =head2 SetFinalPriority VALUE
1442 Set FinalPriority to VALUE.
1443 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1444 (In the database, FinalPriority will be stored as a int(11).)
1452 Returns the current value of DefaultDueIn.
1453 (In the database, DefaultDueIn is stored as int(11).)
1457 =head2 SetDefaultDueIn VALUE
1460 Set DefaultDueIn to VALUE.
1461 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1462 (In the database, DefaultDueIn will be stored as a int(11).)
1470 Returns the current value of Creator.
1471 (In the database, Creator is stored as int(11).)
1479 Returns the current value of Created.
1480 (In the database, Created is stored as datetime.)
1486 =head2 LastUpdatedBy
1488 Returns the current value of LastUpdatedBy.
1489 (In the database, LastUpdatedBy is stored as int(11).)
1497 Returns the current value of LastUpdated.
1498 (In the database, LastUpdated is stored as datetime.)
1506 Returns the current value of Disabled.
1507 (In the database, Disabled is stored as smallint(6).)
1511 =head2 SetDisabled VALUE
1514 Set Disabled to VALUE.
1515 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1516 (In the database, Disabled will be stored as a smallint(6).)
1523 sub _CoreAccessible {
1527 {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''},
1529 {read => 1, write => 1, sql_type => 12, length => 200, is_blob => 0, is_numeric => 0, type => 'varchar(200)', default => ''},
1531 {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''},
1532 CorrespondAddress =>
1533 {read => 1, write => 1, sql_type => 12, length => 120, is_blob => 0, is_numeric => 0, type => 'varchar(120)', default => ''},
1535 {read => 1, write => 1, sql_type => 12, length => 120, is_blob => 0, is_numeric => 0, type => 'varchar(120)', default => ''},
1537 {read => 1, write => 1, sql_type => 12, length => 120, is_blob => 0, is_numeric => 0, type => 'varchar(120)', default => ''},
1539 {read => 1, write => 1, sql_type => 12, length => 32, is_blob => 0, is_numeric => 0, type => 'varchar(32)', default => ''},
1541 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
1543 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
1545 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
1547 {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
1549 {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''},
1551 {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
1553 {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''},
1555 {read => 1, write => 1, sql_type => 5, length => 6, is_blob => 0, is_numeric => 1, type => 'smallint(6)', default => '0'},
1562 RT::Base->_ImportOverlays();