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,
399 _RecordTransaction => 1,
403 unless ( $self->CurrentUser->HasRight(Right => 'AdminQueue', Object => $RT::System) )
405 return ( 0, $self->loc("No permission to create queues") );
409 my ($val, $msg) = $self->_ValidateName( $args{'Name'} );
410 return ($val, $msg) unless $val;
413 if ( $args{'Lifecycle'} && $args{'Lifecycle'} ne 'default' ) {
414 return ( 0, $self->loc('Invalid lifecycle name') )
415 unless $self->ValidateLifecycle( $args{'Lifecycle'} );
417 $args{'Lifecycle'} = undef;
420 my %attrs = map {$_ => 1} $self->ReadableAttributes;
422 #TODO better input validation
423 $RT::Handle->BeginTransaction();
424 my $id = $self->SUPER::Create( map { $_ => $args{$_} } grep exists $args{$_}, keys %attrs );
426 $RT::Handle->Rollback();
427 return ( 0, $self->loc('Queue could not be created') );
430 my $create_ret = $self->_CreateQueueGroups();
431 unless ($create_ret) {
432 $RT::Handle->Rollback();
433 return ( 0, $self->loc('Queue could not be created') );
435 if ( $args{'_RecordTransaction'} ) {
436 $self->_NewTransaction( Type => "Create" );
440 for my $attr (qw/Sign SignAuto Encrypt/) {
441 next unless defined $args{$attr};
442 my $set = "Set" . $attr;
443 my ($status, $msg) = $self->$set( $args{$attr} );
444 $RT::Logger->error("Couldn't set attribute '$attr': $msg")
448 RT->System->QueueCacheNeedsUpdate(1);
450 return ( $id, $self->loc("Queue created") );
458 $self->loc('Deleting this object would break referential integrity') );
466 1 will cause this queue to no longer be available for tickets.
467 0 will re-enable this queue.
475 $RT::Handle->BeginTransaction();
476 my $set_err = $self->_Set( Field =>'Disabled', Value => $val);
478 $RT::Handle->Rollback();
479 $RT::Logger->warning("Couldn't ".($val == 1) ? "disable" : "enable"." queue ".$self->PrincipalObj->Id);
482 $self->_NewTransaction( Type => ($val == 1) ? "Disabled" : "Enabled" );
484 $RT::Handle->Commit();
486 RT->System->QueueCacheNeedsUpdate(1);
489 return (1, $self->loc("Queue disabled"));
491 return (1, $self->loc("Queue enabled"));
500 Takes either a numerical id or a textual Name and loads the specified queue.
507 my $identifier = shift;
508 if ( !$identifier ) {
512 if ( $identifier =~ /^(\d+)$/ ) {
513 $self->SUPER::LoadById($identifier);
516 $self->LoadByCols( Name => $identifier );
519 return ( $self->Id );
525 =head2 ValidateName NAME
527 Takes a queue name. Returns true if it's an ok name for
528 a new queue. Returns undef if there's already a queue by that name.
536 my ($ok, $msg) = $self->_ValidateName($name);
545 return (undef, "Queue name is required") unless length $name;
547 # Validate via the superclass first
548 # Case: short circuit if it's an integer so we don't have
549 # fale negatives when loading a temp queue
550 unless ( my $q = $self->SUPER::ValidateName($name) ) {
551 return ($q, $self->loc("'[_1]' is not a valid name.", $name));
554 my $tempqueue = RT::Queue->new(RT->SystemUser);
555 $tempqueue->Load($name);
557 #If this queue exists, return undef
558 if ( $tempqueue->Name() && $tempqueue->id != $self->id) {
559 return (undef, $self->loc("Queue already exists") );
574 return undef unless $self->CurrentUserHasRight('SeeQueue');
575 my $attr = $self->FirstAttribute('Sign') or return 0;
576 return $attr->Content;
583 return ( 0, $self->loc('Permission Denied') )
584 unless $self->CurrentUserHasRight('AdminQueue');
586 my ($status, $msg) = $self->SetAttribute(
588 Description => 'Sign outgoing messages by default',
591 return ($status, $msg) unless $status;
592 return ($status, $self->loc('Signing enabled')) if $value;
593 return ($status, $self->loc('Signing disabled'));
600 return undef unless $self->CurrentUserHasRight('SeeQueue');
601 my $attr = $self->FirstAttribute('SignAuto') or return 0;
602 return $attr->Content;
609 return ( 0, $self->loc('Permission Denied') )
610 unless $self->CurrentUserHasRight('AdminQueue');
612 my ($status, $msg) = $self->SetAttribute(
614 Description => 'Sign auto-generated outgoing messages',
617 return ($status, $msg) unless $status;
618 return ($status, $self->loc('Signing enabled')) if $value;
619 return ($status, $self->loc('Signing disabled'));
626 return undef unless $self->CurrentUserHasRight('SeeQueue');
627 my $attr = $self->FirstAttribute('Encrypt') or return 0;
628 return $attr->Content;
635 return ( 0, $self->loc('Permission Denied') )
636 unless $self->CurrentUserHasRight('AdminQueue');
638 my ($status, $msg) = $self->SetAttribute(
640 Description => 'Encrypt outgoing messages by default',
643 return ($status, $msg) unless $status;
644 return ($status, $self->loc('Encrypting enabled')) if $value;
645 return ($status, $self->loc('Encrypting disabled'));
650 Returns an RT::Templates object of all of this queue's templates.
657 my $templates = RT::Templates->new( $self->CurrentUser );
659 if ( $self->CurrentUserHasRight('ShowTemplate') ) {
660 $templates->LimitToQueue( $self->id );
669 =head2 CustomField NAME
671 Load the queue-specific custom field named NAME
678 my $cf = RT::CustomField->new($self->CurrentUser);
679 $cf->LoadByNameAndQueue(Name => $name, Queue => $self->Id);
685 =head2 TicketCustomFields
687 Returns an L<RT::CustomFields> object containing all global and
688 queue-specific B<ticket> custom fields.
692 sub TicketCustomFields {
695 my $cfs = RT::CustomFields->new( $self->CurrentUser );
696 if ( $self->CurrentUserHasRight('SeeQueue') ) {
697 $cfs->SetContextObject( $self );
698 $cfs->LimitToGlobalOrObjectId( $self->Id );
699 $cfs->LimitToLookupType( 'RT::Queue-RT::Ticket' );
700 $cfs->ApplySortOrder;
707 =head2 TicketTransactionCustomFields
709 Returns an L<RT::CustomFields> object containing all global and
710 queue-specific B<transaction> custom fields.
714 sub TicketTransactionCustomFields {
717 my $cfs = RT::CustomFields->new( $self->CurrentUser );
718 if ( $self->CurrentUserHasRight('SeeQueue') ) {
719 $cfs->SetContextObject( $self );
720 $cfs->LimitToGlobalOrObjectId( $self->Id );
721 $cfs->LimitToLookupType( 'RT::Queue-RT::Ticket-RT::Transaction' );
722 $cfs->ApplySortOrder;
731 =head2 AllRoleGroupTypes
733 Returns a list of the names of the various role group types that this queue
734 has, including Requestor and Owner. If you don't want them, see
735 L</ManageableRoleGroupTypes>.
739 sub AllRoleGroupTypes {
741 return ($self->ManageableRoleGroupTypes, qw(Requestor Owner));
744 =head2 IsRoleGroupType
746 Returns whether the passed-in type is a role group type.
750 sub IsRoleGroupType {
754 for my $valid_type ($self->AllRoleGroupTypes) {
755 return 1 if $type eq $valid_type;
761 =head2 ManageableRoleGroupTypes
763 Returns a list of the names of the various role group types that this queue
764 has, excluding Requestor and Owner. If you want them, see L</AllRoleGroupTypes>.
768 sub ManageableRoleGroupTypes {
769 return qw(Cc AdminCc);
772 =head2 IsManageableRoleGroupType
774 Returns whether the passed-in type is a manageable role group type.
778 sub IsManageableRoleGroupType {
782 for my $valid_type ($self->ManageableRoleGroupTypes) {
783 return 1 if $type eq $valid_type;
790 =head2 _CreateQueueGroups
792 Create the ticket groups and links for this ticket.
793 This routine expects to be called from Ticket->Create _inside of a transaction_
795 It will create four groups for this ticket: Requestor, Cc, AdminCc and Owner.
797 It will return true on success and undef on failure.
802 sub _CreateQueueGroups {
805 my @types = $self->AllRoleGroupTypes;
807 foreach my $type (@types) {
808 my $ok = $self->_CreateQueueRoleGroup($type);
809 return undef if !$ok;
815 sub _CreateQueueRoleGroup {
819 my $type_obj = RT::Group->new($self->CurrentUser);
820 my ($id, $msg) = $type_obj->CreateRoleGroup(Instance => $self->Id,
822 Domain => 'RT::Queue-Role');
824 $RT::Logger->error("Couldn't create a Queue group of type '$type' for queue ".
825 $self->Id.": ".$msg);
834 # _HasModifyWatcherRight {{{
835 sub _HasModifyWatcherRight {
839 PrincipalId => undef,
844 return 1 if $self->CurrentUserHasRight('ModifyQueueWatchers');
846 #If the watcher we're trying to add is for the current user
847 if ( defined $args{'PrincipalId'} && $self->CurrentUser->PrincipalId eq $args{'PrincipalId'}) {
848 if ( $args{'Type'} eq 'AdminCc' ) {
849 return 1 if $self->CurrentUserHasRight('WatchAsAdminCc');
851 elsif ( $args{'Type'} eq 'Cc' or $args{'Type'} eq 'Requestor' ) {
852 return 1 if $self->CurrentUserHasRight('Watch');
855 $RT::Logger->warning( "$self -> _HasModifyWatcher got passed a bogus type $args{Type}");
856 return ( 0, $self->loc('Invalid queue role group type [_1]', $args{Type}) );
860 return ( 0, $self->loc("Permission Denied") );
866 AddWatcher takes a parameter hash. The keys are as follows:
868 Type One of Requestor, Cc, AdminCc
870 PrinicpalId The RT::Principal id of the user or group that's being added as a watcher
871 Email The email address of the new watcher. If a user with this
872 email address can't be found, a new nonprivileged user will be created.
874 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.
876 Returns a tuple of (status/id, message).
884 PrincipalId => undef,
889 return ( 0, "No principal specified" )
890 unless $args{'Email'} or $args{'PrincipalId'};
892 if ( !$args{'PrincipalId'} && $args{'Email'} ) {
893 my $user = RT::User->new( $self->CurrentUser );
894 $user->LoadByEmail( $args{'Email'} );
895 $args{'PrincipalId'} = $user->PrincipalId if $user->id;
898 return ( 0, "Unknown watcher type [_1]", $args{Type} )
899 unless $self->IsRoleGroupType($args{Type});
901 my ($ok, $msg) = $self->_HasModifyWatcherRight(%args);
902 return ($ok, $msg) if !$ok;
904 return $self->_AddWatcher(%args);
907 #This contains the meat of AddWatcher. but can be called from a routine like
908 # Create, which doesn't need the additional acl check
914 PrincipalId => undef,
920 my $principal = RT::Principal->new( $self->CurrentUser );
921 if ( $args{'PrincipalId'} ) {
922 $principal->Load( $args{'PrincipalId'} );
923 if ( $principal->id and $principal->IsUser and my $email = $principal->Object->EmailAddress ) {
924 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'})))
925 if RT::EmailParser->IsRTAddress( $email );
928 elsif ( $args{'Email'} ) {
929 if ( RT::EmailParser->IsRTAddress( $args{'Email'} ) ) {
930 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'})));
932 my $user = RT::User->new($self->CurrentUser);
933 $user->LoadByEmail( $args{'Email'} );
934 $user->Load( $args{'Email'} )
937 if ( $user->Id ) { # If the user exists
938 $principal->Load( $user->PrincipalId );
940 # if the user doesn't exist, we need to create a new user
941 my $new_user = RT::User->new(RT->SystemUser);
943 my ( $Address, $Name ) =
944 RT::Interface::Email::ParseAddressFromHeader($args{'Email'});
946 my ( $Val, $Message ) = $new_user->Create(
948 EmailAddress => $Address,
951 Comments => 'Autocreated when added as a watcher'
954 $RT::Logger->error("Failed to create user ".$args{'Email'} .": " .$Message);
955 # Deal with the race condition of two account creations at once
956 $new_user->LoadByEmail( $args{'Email'} );
958 $principal->Load( $new_user->PrincipalId );
961 # If we can't find this watcher, we need to bail.
962 unless ( $principal->Id ) {
963 return(0, $self->loc("Could not find or create that user"));
966 my $group = RT::Group->new($self->CurrentUser);
967 $group->LoadQueueRoleGroup(Type => $args{'Type'}, Queue => $self->Id);
968 unless ($group->id) {
969 return(0,$self->loc("Group not found"));
972 if ( $group->HasMember( $principal)) {
974 return ( 0, $self->loc('That principal is already a [_1] for this queue', $args{'Type'}) );
978 my ($m_id, $m_msg) = $group->_AddMember(PrincipalId => $principal->Id);
980 $RT::Logger->error("Failed to add ".$principal->Id." as a member of group ".$group->Id.": ".$m_msg);
982 return ( 0, $self->loc('Could not make that principal a [_1] for this queue', $args{'Type'}) );
984 return ( 1, $self->loc("Added [_1] to members of [_2] for this queue.", $principal->Object->Name, $args{'Type'} ));
989 =head2 DeleteWatcher { Type => TYPE, PrincipalId => PRINCIPAL_ID, Email => EMAIL_ADDRESS }
992 Deletes a queue watcher. Takes two arguments:
994 Type (one of Requestor,Cc,AdminCc)
998 PrincipalId (an RT::Principal Id of the watcher you want to remove)
1000 Email (the email address of an existing wathcer)
1009 my %args = ( Type => undef,
1010 PrincipalId => undef,
1014 unless ( $args{'PrincipalId'} || $args{'Email'} ) {
1015 return ( 0, $self->loc("No principal specified") );
1018 if ( !$args{PrincipalId} and $args{Email} ) {
1019 my $user = RT::User->new( $self->CurrentUser );
1020 my ($rv, $msg) = $user->LoadByEmail( $args{Email} );
1021 $args{PrincipalId} = $user->PrincipalId if $rv;
1024 my $principal = RT::Principal->new( $self->CurrentUser );
1025 if ( $args{'PrincipalId'} ) {
1026 $principal->Load( $args{'PrincipalId'} );
1029 my $user = RT::User->new( $self->CurrentUser );
1030 $user->LoadByEmail( $args{'Email'} );
1031 $principal->Load( $user->Id );
1034 # If we can't find this watcher, we need to bail.
1035 unless ( $principal->Id ) {
1036 return ( 0, $self->loc("Could not find that principal") );
1039 my $group = RT::Group->new($self->CurrentUser);
1040 $group->LoadQueueRoleGroup(Type => $args{'Type'}, Queue => $self->Id);
1041 unless ($group->id) {
1042 return(0,$self->loc("Group not found"));
1045 return ( 0, $self->loc('Unknown watcher type [_1]', $args{Type}) )
1046 unless $self->IsRoleGroupType($args{Type});
1048 my ($ok, $msg) = $self->_HasModifyWatcherRight(%args);
1049 return ($ok, $msg) if !$ok;
1051 # see if this user is already a watcher.
1053 unless ( $group->HasMember($principal)) {
1055 $self->loc('That principal is not a [_1] for this queue', $args{'Type'}) );
1058 my ($m_id, $m_msg) = $group->_DeleteMember($principal->Id);
1060 $RT::Logger->error("Failed to delete ".$principal->Id.
1061 " as a member of group ".$group->Id.": ".$m_msg);
1063 return ( 0, $self->loc('Could not remove that principal as a [_1] for this queue', $args{'Type'}) );
1066 return ( 1, $self->loc("Removed [_1] from members of [_2] for this queue.", $principal->Object->Name, $args{'Type'} ));
1071 =head2 AdminCcAddresses
1073 returns String: All queue AdminCc email addresses as a string
1077 sub AdminCcAddresses {
1080 unless ( $self->CurrentUserHasRight('SeeQueue') ) {
1084 return ( $self->AdminCc->MemberEmailAddressesAsString )
1092 returns String: All queue Ccs as a string of email addresses
1099 unless ( $self->CurrentUserHasRight('SeeQueue') ) {
1103 return ( $self->Cc->MemberEmailAddressesAsString);
1112 Returns an RT::Group object which contains this Queue's Ccs.
1113 If the user doesn't have "ShowQueue" permission, returns an empty group
1120 my $group = RT::Group->new($self->CurrentUser);
1121 if ( $self->CurrentUserHasRight('SeeQueue') ) {
1122 $group->LoadQueueRoleGroup(Type => 'Cc', Queue => $self->Id);
1133 Returns an RT::Group object which contains this Queue's AdminCcs.
1134 If the user doesn't have "ShowQueue" permission, returns an empty group
1141 my $group = RT::Group->new($self->CurrentUser);
1142 if ( $self->CurrentUserHasRight('SeeQueue') ) {
1143 $group->LoadQueueRoleGroup(Type => 'AdminCc', Queue => $self->Id);
1151 # a generic routine to be called by IsRequestor, IsCc and IsAdminCc
1153 =head2 IsWatcher { Type => TYPE, PrincipalId => PRINCIPAL_ID }
1155 Takes a param hash with the attributes Type and PrincipalId
1157 Type is one of Requestor, Cc, AdminCc and Owner
1159 PrincipalId is an RT::Principal id
1161 Returns true if that principal is a member of the group Type for this queue
1169 my %args = ( Type => 'Cc',
1170 PrincipalId => undef,
1174 # Load the relevant group.
1175 my $group = RT::Group->new($self->CurrentUser);
1176 $group->LoadQueueRoleGroup(Type => $args{'Type'}, Queue => $self->id);
1177 # Ask if it has the member in question
1179 my $principal = RT::Principal->new($self->CurrentUser);
1180 $principal->Load($args{'PrincipalId'});
1181 unless ($principal->Id) {
1185 return ($group->HasMemberRecursively($principal));
1191 =head2 IsCc PRINCIPAL_ID
1193 Takes an RT::Principal id.
1194 Returns true if the principal is a requestor of the current queue.
1203 return ( $self->IsWatcher( Type => 'Cc', PrincipalId => $cc ) );
1209 =head2 IsAdminCc PRINCIPAL_ID
1211 Takes an RT::Principal id.
1212 Returns true if the principal is a requestor of the current queue.
1220 return ( $self->IsWatcher( Type => 'AdminCc', PrincipalId => $person ) );
1236 unless ( $self->CurrentUserHasRight('AdminQueue') ) {
1237 return ( 0, $self->loc('Permission Denied') );
1239 return ( $self->SUPER::_Set(@_) );
1247 unless ( $self->CurrentUserHasRight('SeeQueue') ) {
1251 return ( $self->__Value(@_) );
1256 =head2 CurrentUserHasRight
1258 Takes one argument. A textual string with the name of the right we want to check.
1259 Returns true if the current user has that right for this queue.
1260 Returns undef otherwise.
1264 sub CurrentUserHasRight {
1270 Principal => $self->CurrentUser,
1277 =head2 CurrentUserCanSee
1279 Returns true if the current user can see the queue, using SeeQueue
1283 sub CurrentUserCanSee {
1286 return $self->CurrentUserHasRight('SeeQueue');
1292 Takes a param hash with the fields 'Right' and 'Principal'.
1293 Principal defaults to the current user.
1294 Returns true if the principal has that right for this queue.
1295 Returns undef otherwise.
1299 # TAKES: Right and optional "Principal" which defaults to the current user
1304 Principal => $self->CurrentUser,
1307 my $principal = delete $args{'Principal'};
1308 unless ( $principal ) {
1309 $RT::Logger->error("Principal undefined in Queue::HasRight");
1313 return $principal->HasRight(
1315 Object => ($self->Id ? $self : $RT::System),
1324 Returns the current value of id.
1325 (In the database, id is stored as int(11).)
1333 Returns the current value of Name.
1334 (In the database, Name is stored as varchar(200).)
1338 =head2 SetName VALUE
1342 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1343 (In the database, Name will be stored as a varchar(200).)
1351 Returns the current value of Description.
1352 (In the database, Description is stored as varchar(255).)
1356 =head2 SetDescription VALUE
1359 Set Description to VALUE.
1360 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1361 (In the database, Description will be stored as a varchar(255).)
1367 =head2 CorrespondAddress
1369 Returns the current value of CorrespondAddress.
1370 (In the database, CorrespondAddress is stored as varchar(120).)
1374 =head2 SetCorrespondAddress VALUE
1377 Set CorrespondAddress to VALUE.
1378 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1379 (In the database, CorrespondAddress will be stored as a varchar(120).)
1385 =head2 CommentAddress
1387 Returns the current value of CommentAddress.
1388 (In the database, CommentAddress is stored as varchar(120).)
1392 =head2 SetCommentAddress VALUE
1395 Set CommentAddress to VALUE.
1396 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1397 (In the database, CommentAddress will be stored as a varchar(120).)
1405 Returns the current value of Lifecycle.
1406 (In the database, Lifecycle is stored as varchar(32).)
1410 =head2 SetLifecycle VALUE
1413 Set Lifecycle to VALUE.
1414 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1415 (In the database, Lifecycle will be stored as a varchar(32).)
1422 Returns the current value of SubjectTag.
1423 (In the database, SubjectTag is stored as varchar(120).)
1427 =head2 SetSubjectTag VALUE
1430 Set SubjectTag to VALUE.
1431 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1432 (In the database, SubjectTag will be stored as a varchar(120).)
1438 =head2 InitialPriority
1440 Returns the current value of InitialPriority.
1441 (In the database, InitialPriority is stored as int(11).)
1445 =head2 SetInitialPriority VALUE
1448 Set InitialPriority to VALUE.
1449 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1450 (In the database, InitialPriority will be stored as a int(11).)
1456 =head2 FinalPriority
1458 Returns the current value of FinalPriority.
1459 (In the database, FinalPriority is stored as int(11).)
1463 =head2 SetFinalPriority VALUE
1466 Set FinalPriority to VALUE.
1467 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1468 (In the database, FinalPriority will be stored as a int(11).)
1476 Returns the current value of DefaultDueIn.
1477 (In the database, DefaultDueIn is stored as int(11).)
1481 =head2 SetDefaultDueIn VALUE
1484 Set DefaultDueIn to VALUE.
1485 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1486 (In the database, DefaultDueIn will be stored as a int(11).)
1494 Returns the current value of Creator.
1495 (In the database, Creator is stored as int(11).)
1503 Returns the current value of Created.
1504 (In the database, Created is stored as datetime.)
1510 =head2 LastUpdatedBy
1512 Returns the current value of LastUpdatedBy.
1513 (In the database, LastUpdatedBy is stored as int(11).)
1521 Returns the current value of LastUpdated.
1522 (In the database, LastUpdated is stored as datetime.)
1530 Returns the current value of Disabled.
1531 (In the database, Disabled is stored as smallint(6).)
1535 =head2 SetDisabled VALUE
1538 Set Disabled to VALUE.
1539 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1540 (In the database, Disabled will be stored as a smallint(6).)
1547 sub _CoreAccessible {
1551 {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''},
1553 {read => 1, write => 1, sql_type => 12, length => 200, is_blob => 0, is_numeric => 0, type => 'varchar(200)', default => ''},
1555 {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''},
1556 CorrespondAddress =>
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 => 120, is_blob => 0, is_numeric => 0, type => 'varchar(120)', default => ''},
1563 {read => 1, write => 1, sql_type => 12, length => 32, is_blob => 0, is_numeric => 0, type => 'varchar(32)', default => ''},
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, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
1571 {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
1573 {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''},
1575 {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
1577 {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''},
1579 {read => 1, write => 1, sql_type => 5, length => 6, is_blob => 0, is_numeric => 1, type => 'smallint(6)', default => '0'},
1586 RT::Base->_ImportOverlays();