Merge branch 'master' of git.uio.no:usit-rt
[usit-rt.git] / lib / RT / Queue.pm
CommitLineData
84fb5b46
MKG
1# BEGIN BPS TAGGED BLOCK {{{
2#
3# COPYRIGHT:
4#
320f0092 5# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC
84fb5b46
MKG
6# <sales@bestpractical.com>
7#
8# (Except where explicitly superseded by other copyright notices)
9#
10#
11# LICENSE:
12#
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
16# from www.gnu.org.
17#
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.
22#
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.
28#
29#
30# CONTRIBUTION SUBMISSION POLICY:
31#
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.)
37#
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.
46#
47# END BPS TAGGED BLOCK }}}
48
49=head1 NAME
50
51 RT::Queue - an RT Queue object
52
53=head1 SYNOPSIS
54
55 use RT::Queue;
56
57=head1 DESCRIPTION
58
59An RT queue object.
60
61=head1 METHODS
62
63=cut
64
65
66package RT::Queue;
67
68use strict;
69use warnings;
70use base 'RT::Record';
71
af59614d
MKG
72use Role::Basic 'with';
73with "RT::Record::Role::Lifecycle",
74 "RT::Record::Role::Links" => { -excludes => ["_AddLinksOnCreate"] },
75 "RT::Record::Role::Roles",
76 "RT::Record::Role::Rights";
77
84fb5b46
MKG
78sub Table {'Queues'}
79
af59614d
MKG
80sub LifecycleType { "ticket" }
81
82sub ModifyLinkRight { "AdminQueue" }
84fb5b46 83
af59614d
MKG
84require RT::ACE;
85RT::ACE->RegisterCacheHandler(sub {
86 my %args = (
87 Action => "",
88 RightName => "",
89 @_
90 );
91
92 return unless $args{Action} =~ /^(Grant|Revoke)$/i
93 and $args{RightName} =~ /^(SeeQueue|CreateTicket)$/;
94
95 RT->System->QueueCacheNeedsUpdate(1);
96});
84fb5b46
MKG
97
98use RT::Groups;
99use RT::ACL;
100use RT::Interface::Email;
101
84fb5b46
MKG
102# $self->loc('new'); # For the string extractor to get a string to localize
103# $self->loc('open'); # For the string extractor to get a string to localize
104# $self->loc('stalled'); # For the string extractor to get a string to localize
105# $self->loc('resolved'); # For the string extractor to get a string to localize
106# $self->loc('rejected'); # For the string extractor to get a string to localize
107# $self->loc('deleted'); # For the string extractor to get a string to localize
108
320f0092
MKG
109__PACKAGE__->AddRight( General => SeeQueue => 'View queue' ); # loc
110__PACKAGE__->AddRight( Admin => AdminQueue => 'Create, modify and delete queue' ); # loc
111__PACKAGE__->AddRight( Admin => ShowACL => 'Display Access Control List' ); # loc
112__PACKAGE__->AddRight( Admin => ModifyACL => 'Create, modify and delete Access Control List entries' ); # loc
113__PACKAGE__->AddRight( Admin => ModifyQueueWatchers => 'Modify queue watchers' ); # loc
114__PACKAGE__->AddRight( General => SeeCustomField => 'View custom field values' ); # loc
115__PACKAGE__->AddRight( Staff => ModifyCustomField => 'Modify custom field values' ); # loc
116__PACKAGE__->AddRight( Admin => AssignCustomFields => 'Assign and remove queue custom fields' ); # loc
117__PACKAGE__->AddRight( Admin => ModifyTemplate => 'Modify Scrip templates' ); # loc
118__PACKAGE__->AddRight( Admin => ShowTemplate => 'View Scrip templates' ); # loc
119
120__PACKAGE__->AddRight( Admin => ModifyScrips => 'Modify Scrips' ); # loc
121__PACKAGE__->AddRight( Admin => ShowScrips => 'View Scrips' ); # loc
122
123__PACKAGE__->AddRight( General => ShowTicket => 'View ticket summaries' ); # loc
124__PACKAGE__->AddRight( Staff => ShowTicketComments => 'View ticket private commentary' ); # loc
125__PACKAGE__->AddRight( Staff => ShowOutgoingEmail => 'View exact outgoing email messages and their recipients' ); # loc
126
127__PACKAGE__->AddRight( General => Watch => 'Sign up as a ticket Requestor or ticket or queue Cc' ); # loc
128__PACKAGE__->AddRight( Staff => WatchAsAdminCc => 'Sign up as a ticket or queue AdminCc' ); # loc
129__PACKAGE__->AddRight( General => CreateTicket => 'Create tickets' ); # loc
130__PACKAGE__->AddRight( General => ReplyToTicket => 'Reply to tickets' ); # loc
131__PACKAGE__->AddRight( General => CommentOnTicket => 'Comment on tickets' ); # loc
132__PACKAGE__->AddRight( Staff => OwnTicket => 'Own tickets' ); # loc
133__PACKAGE__->AddRight( Staff => ModifyTicket => 'Modify tickets' ); # loc
134__PACKAGE__->AddRight( Staff => DeleteTicket => 'Delete tickets' ); # loc
135__PACKAGE__->AddRight( Staff => TakeTicket => 'Take tickets' ); # loc
136__PACKAGE__->AddRight( Staff => StealTicket => 'Steal tickets' ); # loc
137__PACKAGE__->AddRight( Staff => ReassignTicket => 'Modify ticket owner on owned tickets' ); # loc
138
139__PACKAGE__->AddRight( Staff => ForwardMessage => 'Forward messages outside of RT' ); # loc
84fb5b46
MKG
140
141=head2 Create(ARGS)
142
143Arguments: ARGS is a hash of named parameters. Valid parameters are:
144
145 Name (required)
146 Description
147 CorrespondAddress
148 CommentAddress
149 InitialPriority
150 FinalPriority
151 DefaultDueIn
152
153If you pass the ACL check, it creates the queue and returns its queue id.
154
155
156=cut
157
158sub Create {
159 my $self = shift;
160 my %args = (
161 Name => undef,
162 Description => '',
163 CorrespondAddress => '',
164 CommentAddress => '',
165 Lifecycle => 'default',
166 SubjectTag => undef,
167 InitialPriority => 0,
168 FinalPriority => 0,
169 DefaultDueIn => 0,
170 Sign => undef,
dab09ea8 171 SignAuto => undef,
84fb5b46
MKG
172 Encrypt => undef,
173 _RecordTransaction => 1,
174 @_
175 );
176
177 unless ( $self->CurrentUser->HasRight(Right => 'AdminQueue', Object => $RT::System) )
178 { #Check them ACLs
179 return ( 0, $self->loc("No permission to create queues") );
180 }
181
182 {
183 my ($val, $msg) = $self->_ValidateName( $args{'Name'} );
184 return ($val, $msg) unless $val;
185 }
186
403d7b0b
MKG
187 $args{'Lifecycle'} ||= 'default';
188
189 return ( 0, $self->loc('[_1] is not a valid lifecycle', $args{'Lifecycle'} ) )
190 unless $self->ValidateLifecycle( $args{'Lifecycle'} );
84fb5b46
MKG
191
192 my %attrs = map {$_ => 1} $self->ReadableAttributes;
193
194 #TODO better input validation
195 $RT::Handle->BeginTransaction();
196 my $id = $self->SUPER::Create( map { $_ => $args{$_} } grep exists $args{$_}, keys %attrs );
197 unless ($id) {
198 $RT::Handle->Rollback();
199 return ( 0, $self->loc('Queue could not be created') );
200 }
201
af59614d 202 my $create_ret = $self->_CreateRoleGroups();
84fb5b46
MKG
203 unless ($create_ret) {
204 $RT::Handle->Rollback();
205 return ( 0, $self->loc('Queue could not be created') );
206 }
207 if ( $args{'_RecordTransaction'} ) {
208 $self->_NewTransaction( Type => "Create" );
209 }
210 $RT::Handle->Commit;
211
dab09ea8
MKG
212 for my $attr (qw/Sign SignAuto Encrypt/) {
213 next unless defined $args{$attr};
214 my $set = "Set" . $attr;
215 my ($status, $msg) = $self->$set( $args{$attr} );
216 $RT::Logger->error("Couldn't set attribute '$attr': $msg")
84fb5b46
MKG
217 unless $status;
218 }
219
220 RT->System->QueueCacheNeedsUpdate(1);
221
222 return ( $id, $self->loc("Queue created") );
223}
224
225
226
227sub Delete {
228 my $self = shift;
229 return ( 0,
230 $self->loc('Deleting this object would break referential integrity') );
231}
232
233
234
235=head2 SetDisabled
236
237Takes a boolean.
2381 will cause this queue to no longer be available for tickets.
2390 will re-enable this queue.
240
241=cut
242
243sub SetDisabled {
244 my $self = shift;
245 my $val = shift;
246
247 $RT::Handle->BeginTransaction();
c33a4027
MKG
248 my ($ok, $msg) = $self->_Set( Field =>'Disabled', Value => $val);
249 unless ($ok) {
84fb5b46 250 $RT::Handle->Rollback();
c33a4027
MKG
251 $RT::Logger->warning("Couldn't ".(($val == 0) ? "enable" : "disable")." queue ".$self->Name.": $msg");
252 return ($ok, $msg);
84fb5b46 253 }
c33a4027 254 $self->_NewTransaction( Type => ($val == 0) ? "Enabled" : "Disabled" );
84fb5b46
MKG
255
256 $RT::Handle->Commit();
257
258 RT->System->QueueCacheNeedsUpdate(1);
259
c33a4027 260 if ( $val == 0 ) {
84fb5b46 261 return (1, $self->loc("Queue enabled"));
c33a4027
MKG
262 } else {
263 return (1, $self->loc("Queue disabled"));
84fb5b46
MKG
264 }
265
266}
267
268
269
270=head2 Load
271
272Takes either a numerical id or a textual Name and loads the specified queue.
273
274=cut
275
276sub Load {
277 my $self = shift;
278
279 my $identifier = shift;
280 if ( !$identifier ) {
281 return (undef);
282 }
283
284 if ( $identifier =~ /^(\d+)$/ ) {
285 $self->SUPER::LoadById($identifier);
286 }
287 else {
288 $self->LoadByCols( Name => $identifier );
289 }
290
291 return ( $self->Id );
292
293}
294
295
296
297=head2 ValidateName NAME
298
299Takes a queue name. Returns true if it's an ok name for
300a new queue. Returns undef if there's already a queue by that name.
301
302=cut
303
304sub ValidateName {
305 my $self = shift;
306 my $name = shift;
307
308 my ($ok, $msg) = $self->_ValidateName($name);
309
310 return $ok ? 1 : 0;
311}
312
313sub _ValidateName {
314 my $self = shift;
315 my $name = shift;
316
317 return (undef, "Queue name is required") unless length $name;
318
319 # Validate via the superclass first
320 # Case: short circuit if it's an integer so we don't have
321 # fale negatives when loading a temp queue
322 unless ( my $q = $self->SUPER::ValidateName($name) ) {
323 return ($q, $self->loc("'[_1]' is not a valid name.", $name));
324 }
325
326 my $tempqueue = RT::Queue->new(RT->SystemUser);
327 $tempqueue->Load($name);
328
329 #If this queue exists, return undef
330 if ( $tempqueue->Name() && $tempqueue->id != $self->id) {
331 return (undef, $self->loc("Queue already exists") );
332 }
333
334 return (1);
335}
336
337
338=head2 SetSign
339
340=cut
341
342sub Sign {
343 my $self = shift;
344 my $value = shift;
345
346 return undef unless $self->CurrentUserHasRight('SeeQueue');
347 my $attr = $self->FirstAttribute('Sign') or return 0;
348 return $attr->Content;
349}
350
351sub SetSign {
352 my $self = shift;
353 my $value = shift;
354
355 return ( 0, $self->loc('Permission Denied') )
356 unless $self->CurrentUserHasRight('AdminQueue');
357
358 my ($status, $msg) = $self->SetAttribute(
359 Name => 'Sign',
360 Description => 'Sign outgoing messages by default',
361 Content => $value,
362 );
363 return ($status, $msg) unless $status;
dab09ea8
MKG
364 return ($status, $self->loc('Signing enabled')) if $value;
365 return ($status, $self->loc('Signing disabled'));
366}
367
368sub SignAuto {
369 my $self = shift;
370 my $value = shift;
371
372 return undef unless $self->CurrentUserHasRight('SeeQueue');
373 my $attr = $self->FirstAttribute('SignAuto') or return 0;
374 return $attr->Content;
375}
376
377sub SetSignAuto {
378 my $self = shift;
379 my $value = shift;
380
381 return ( 0, $self->loc('Permission Denied') )
382 unless $self->CurrentUserHasRight('AdminQueue');
383
384 my ($status, $msg) = $self->SetAttribute(
385 Name => 'SignAuto',
386 Description => 'Sign auto-generated outgoing messages',
387 Content => $value,
388 );
389 return ($status, $msg) unless $status;
84fb5b46
MKG
390 return ($status, $self->loc('Signing enabled')) if $value;
391 return ($status, $self->loc('Signing disabled'));
392}
393
394sub Encrypt {
395 my $self = shift;
396 my $value = shift;
397
398 return undef unless $self->CurrentUserHasRight('SeeQueue');
399 my $attr = $self->FirstAttribute('Encrypt') or return 0;
400 return $attr->Content;
401}
402
403sub SetEncrypt {
404 my $self = shift;
405 my $value = shift;
406
407 return ( 0, $self->loc('Permission Denied') )
408 unless $self->CurrentUserHasRight('AdminQueue');
409
410 my ($status, $msg) = $self->SetAttribute(
411 Name => 'Encrypt',
412 Description => 'Encrypt outgoing messages by default',
413 Content => $value,
414 );
415 return ($status, $msg) unless $status;
416 return ($status, $self->loc('Encrypting enabled')) if $value;
417 return ($status, $self->loc('Encrypting disabled'));
418}
419
420=head2 Templates
421
422Returns an RT::Templates object of all of this queue's templates.
423
424=cut
425
426sub Templates {
427 my $self = shift;
428
429 my $templates = RT::Templates->new( $self->CurrentUser );
430
431 if ( $self->CurrentUserHasRight('ShowTemplate') ) {
432 $templates->LimitToQueue( $self->id );
433 }
434
435 return ($templates);
436}
437
438
439
440
441=head2 CustomField NAME
442
c33a4027
MKG
443Load the Ticket Custom Field applied to this Queue named NAME.
444Does not load Global custom fields.
84fb5b46
MKG
445
446=cut
447
448sub CustomField {
449 my $self = shift;
450 my $name = shift;
451 my $cf = RT::CustomField->new($self->CurrentUser);
c33a4027
MKG
452 $cf->LoadByName(
453 Name => $name,
454 LookupType => RT::Ticket->CustomFieldLookupType,
455 ObjectId => $self->id,
456 );
84fb5b46
MKG
457 return ($cf);
458}
459
460
461
462=head2 TicketCustomFields
463
464Returns an L<RT::CustomFields> object containing all global and
465queue-specific B<ticket> custom fields.
466
467=cut
468
469sub TicketCustomFields {
470 my $self = shift;
471
472 my $cfs = RT::CustomFields->new( $self->CurrentUser );
473 if ( $self->CurrentUserHasRight('SeeQueue') ) {
474 $cfs->SetContextObject( $self );
af59614d
MKG
475 $cfs->LimitToGlobalOrObjectId( $self->Id );
476 $cfs->LimitToLookupType( 'RT::Queue-RT::Ticket' );
84fb5b46
MKG
477 $cfs->ApplySortOrder;
478 }
479 return ($cfs);
480}
481
482
483
484=head2 TicketTransactionCustomFields
485
486Returns an L<RT::CustomFields> object containing all global and
487queue-specific B<transaction> custom fields.
488
489=cut
490
491sub TicketTransactionCustomFields {
492 my $self = shift;
493
494 my $cfs = RT::CustomFields->new( $self->CurrentUser );
495 if ( $self->CurrentUserHasRight('SeeQueue') ) {
496 $cfs->SetContextObject( $self );
af59614d
MKG
497 $cfs->LimitToGlobalOrObjectId( $self->Id );
498 $cfs->LimitToLookupType( 'RT::Queue-RT::Ticket-RT::Transaction' );
84fb5b46
MKG
499 $cfs->ApplySortOrder;
500 }
501 return ($cfs);
502}
503
504
505
506
507
508=head2 AllRoleGroupTypes
509
af59614d
MKG
510B<DEPRECATED> and will be removed in a future release. Use L</Roles>
511instead.
512
513Returns a list of the names of the various role group types for Queues,
514including roles used only for ACLs like Requestor and Owner. If you don't want
515them, see L</ManageableRoleGroupTypes>.
84fb5b46
MKG
516
517=cut
518
519sub AllRoleGroupTypes {
af59614d
MKG
520 RT->Deprecated(
521 Remove => "4.4",
522 Instead => "RT::Queue->Roles",
523 );
524 shift->Roles;
84fb5b46
MKG
525}
526
527=head2 IsRoleGroupType
528
af59614d
MKG
529B<DEPRECATED> and will be removed in a future release. Use L</HasRole> instead.
530
84fb5b46
MKG
531Returns whether the passed-in type is a role group type.
532
533=cut
534
535sub IsRoleGroupType {
af59614d
MKG
536 RT->Deprecated(
537 Remove => "4.4",
538 Instead => "RT::Queue->HasRole",
539 );
540 shift->HasRole(@_);
84fb5b46
MKG
541}
542
543=head2 ManageableRoleGroupTypes
544
af59614d
MKG
545Returns a list of the names of the various role group types for Queues,
546excluding ones used only for ACLs such as Requestor and Owner. If you want
547them, see L</Roles>.
84fb5b46
MKG
548
549=cut
550
551sub ManageableRoleGroupTypes {
af59614d 552 shift->Roles( ACLOnly => 0 )
84fb5b46
MKG
553}
554
555=head2 IsManageableRoleGroupType
556
557Returns whether the passed-in type is a manageable role group type.
558
559=cut
560
561sub IsManageableRoleGroupType {
562 my $self = shift;
563 my $type = shift;
c33a4027 564 return( $self->HasRole($type) and not $self->Role($type)->{ACLOnly} );
84fb5b46
MKG
565}
566
567
84fb5b46
MKG
568sub _HasModifyWatcherRight {
569 my $self = shift;
af59614d 570 my ($type, $principal) = @_;
84fb5b46 571
af59614d 572 # ModifyQueueWatchers works in any case
84fb5b46 573 return 1 if $self->CurrentUserHasRight('ModifyQueueWatchers');
af59614d
MKG
574 # If the watcher isn't the current user then the current user has no right
575 return 0 unless $self->CurrentUser->PrincipalId == $principal->id;
576 # If it's an AdminCc and they don't have 'WatchAsAdminCc', bail
577 return 0 if $type eq 'AdminCc' and not $self->CurrentUserHasRight('WatchAsAdminCc');
578 # If it's a Requestor or Cc and they don't have 'Watch', bail
579 return 0 if ($type eq "Cc" or $type eq 'Requestor')
580 and not $self->CurrentUserHasRight('Watch');
581 return 1;
84fb5b46
MKG
582}
583
584
585=head2 AddWatcher
586
c33a4027
MKG
587Applies access control checking, then calls
588L<RT::Record::Role::Roles/AddRoleMember>. Additionally, C<Email> is
589accepted as an alternative argument name for C<User>.
84fb5b46 590
af59614d 591Returns a tuple of (status, message).
84fb5b46
MKG
592
593=cut
594
595sub AddWatcher {
596 my $self = shift;
597 my %args = (
598 Type => undef,
599 PrincipalId => undef,
600 Email => undef,
601 @_
602 );
603
af59614d
MKG
604 $args{ACL} = sub { $self->_HasModifyWatcherRight( @_ ) };
605 $args{User} ||= delete $args{Email};
606 my ($principal, $msg) = $self->AddRoleMember( %args );
607 return ( 0, $msg) unless $principal;
84fb5b46 608
af59614d
MKG
609 return ( 1, $self->loc("Added [_1] to members of [_2] for this queue.",
610 $principal->Object->Name, $self->loc($args{'Type'}) ));
84fb5b46
MKG
611}
612
84fb5b46 613
af59614d 614=head2 DeleteWatcher
84fb5b46 615
c33a4027
MKG
616Applies access control checking, then calls
617L<RT::Record::Role::Roles/DeleteRoleMember>. Additionally, C<Email> is
618accepted as an alternative argument name for C<User>.
84fb5b46 619
af59614d 620Returns a tuple of (status, message).
84fb5b46
MKG
621
622=cut
623
84fb5b46
MKG
624sub DeleteWatcher {
625 my $self = shift;
626
af59614d
MKG
627 my %args = (
628 Type => undef,
629 PrincipalId => undef,
630 Email => undef,
631 @_
632 );
84fb5b46 633
af59614d
MKG
634 $args{ACL} = sub { $self->_HasModifyWatcherRight( @_ ) };
635 $args{User} ||= delete $args{Email};
636 my ($principal, $msg) = $self->DeleteRoleMember( %args );
637 return ( 0, $msg) unless $principal;
84fb5b46 638
af59614d
MKG
639 return ( 1, $self->loc("Removed [_1] from members of [_2] for this queue.",
640 $principal->Object->Name, $self->loc($args{'Type'}) ));
84fb5b46
MKG
641}
642
643
644
645=head2 AdminCcAddresses
646
647returns String: All queue AdminCc email addresses as a string
648
649=cut
650
651sub AdminCcAddresses {
652 my $self = shift;
653
654 unless ( $self->CurrentUserHasRight('SeeQueue') ) {
655 return undef;
656 }
657
658 return ( $self->AdminCc->MemberEmailAddressesAsString )
659
660}
661
662
663
664=head2 CcAddresses
665
666returns String: All queue Ccs as a string of email addresses
667
668=cut
669
670sub CcAddresses {
671 my $self = shift;
672
673 unless ( $self->CurrentUserHasRight('SeeQueue') ) {
674 return undef;
675 }
676
677 return ( $self->Cc->MemberEmailAddressesAsString);
678
679}
680
681
682
683=head2 Cc
684
685Takes nothing.
686Returns an RT::Group object which contains this Queue's Ccs.
687If the user doesn't have "ShowQueue" permission, returns an empty group
688
689=cut
690
691sub Cc {
692 my $self = shift;
693
af59614d
MKG
694 return RT::Group->new($self->CurrentUser)
695 unless $self->CurrentUserHasRight('SeeQueue');
696 return $self->RoleGroup( 'Cc' );
84fb5b46
MKG
697}
698
699
700
701=head2 AdminCc
702
703Takes nothing.
704Returns an RT::Group object which contains this Queue's AdminCcs.
705If the user doesn't have "ShowQueue" permission, returns an empty group
706
707=cut
708
709sub AdminCc {
710 my $self = shift;
711
af59614d
MKG
712 return RT::Group->new($self->CurrentUser)
713 unless $self->CurrentUserHasRight('SeeQueue');
714 return $self->RoleGroup( 'AdminCc' );
84fb5b46
MKG
715}
716
717
718
719# a generic routine to be called by IsRequestor, IsCc and IsAdminCc
720
721=head2 IsWatcher { Type => TYPE, PrincipalId => PRINCIPAL_ID }
722
723Takes a param hash with the attributes Type and PrincipalId
724
725Type is one of Requestor, Cc, AdminCc and Owner
726
727PrincipalId is an RT::Principal id
728
729Returns true if that principal is a member of the group Type for this queue
730
731
732=cut
733
734sub IsWatcher {
735 my $self = shift;
736
737 my %args = ( Type => 'Cc',
738 PrincipalId => undef,
739 @_
740 );
741
af59614d
MKG
742 # Load the relevant group.
743 my $group = $self->RoleGroup( $args{'Type'} );
84fb5b46
MKG
744 # Ask if it has the member in question
745
746 my $principal = RT::Principal->new($self->CurrentUser);
747 $principal->Load($args{'PrincipalId'});
748 unless ($principal->Id) {
749 return (undef);
750 }
751
752 return ($group->HasMemberRecursively($principal));
753}
754
755
756
757
758=head2 IsCc PRINCIPAL_ID
759
760Takes an RT::Principal id.
761Returns true if the principal is a requestor of the current queue.
762
763
764=cut
765
766sub IsCc {
767 my $self = shift;
768 my $cc = shift;
769
770 return ( $self->IsWatcher( Type => 'Cc', PrincipalId => $cc ) );
771
772}
773
774
775
776=head2 IsAdminCc PRINCIPAL_ID
777
778Takes an RT::Principal id.
779Returns true if the principal is a requestor of the current queue.
780
781=cut
782
783sub IsAdminCc {
784 my $self = shift;
785 my $person = shift;
786
787 return ( $self->IsWatcher( Type => 'AdminCc', PrincipalId => $person ) );
788
789}
790
791
792
793
794
795
796
797
798
799
800sub _Set {
801 my $self = shift;
802
803 unless ( $self->CurrentUserHasRight('AdminQueue') ) {
804 return ( 0, $self->loc('Permission Denied') );
805 }
403d7b0b 806 RT->System->QueueCacheNeedsUpdate(1);
84fb5b46
MKG
807 return ( $self->SUPER::_Set(@_) );
808}
809
810
811
812sub _Value {
813 my $self = shift;
814
815 unless ( $self->CurrentUserHasRight('SeeQueue') ) {
816 return (undef);
817 }
818
819 return ( $self->__Value(@_) );
820}
821
84fb5b46
MKG
822=head2 CurrentUserCanSee
823
824Returns true if the current user can see the queue, using SeeQueue
825
826=cut
827
828sub CurrentUserCanSee {
829 my $self = shift;
830
831 return $self->CurrentUserHasRight('SeeQueue');
832}
833
84fb5b46
MKG
834=head2 id
835
836Returns the current value of id.
837(In the database, id is stored as int(11).)
838
839
840=cut
841
842
843=head2 Name
844
845Returns the current value of Name.
846(In the database, Name is stored as varchar(200).)
847
848
849
850=head2 SetName VALUE
851
852
853Set Name to VALUE.
854Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
855(In the database, Name will be stored as a varchar(200).)
856
857
858=cut
859
860
861=head2 Description
862
863Returns the current value of Description.
864(In the database, Description is stored as varchar(255).)
865
866
867
868=head2 SetDescription VALUE
869
870
871Set Description to VALUE.
872Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
873(In the database, Description will be stored as a varchar(255).)
874
875
876=cut
877
878
879=head2 CorrespondAddress
880
881Returns the current value of CorrespondAddress.
882(In the database, CorrespondAddress is stored as varchar(120).)
883
884
885
886=head2 SetCorrespondAddress VALUE
887
888
889Set CorrespondAddress to VALUE.
890Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
891(In the database, CorrespondAddress will be stored as a varchar(120).)
892
893
894=cut
895
896
897=head2 CommentAddress
898
899Returns the current value of CommentAddress.
900(In the database, CommentAddress is stored as varchar(120).)
901
902
903
904=head2 SetCommentAddress VALUE
905
906
907Set CommentAddress to VALUE.
908Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
909(In the database, CommentAddress will be stored as a varchar(120).)
910
911
912=cut
913
914
915=head2 Lifecycle
916
917Returns the current value of Lifecycle.
918(In the database, Lifecycle is stored as varchar(32).)
919
920
921
922=head2 SetLifecycle VALUE
923
924
925Set Lifecycle to VALUE.
926Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
927(In the database, Lifecycle will be stored as a varchar(32).)
928
929
930=cut
931
932=head2 SubjectTag
933
934Returns the current value of SubjectTag.
935(In the database, SubjectTag is stored as varchar(120).)
936
937
938
939=head2 SetSubjectTag VALUE
940
941
942Set SubjectTag to VALUE.
943Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
944(In the database, SubjectTag will be stored as a varchar(120).)
945
946
947=cut
948
949
950=head2 InitialPriority
951
952Returns the current value of InitialPriority.
953(In the database, InitialPriority is stored as int(11).)
954
955
956
957=head2 SetInitialPriority VALUE
958
959
960Set InitialPriority to VALUE.
961Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
962(In the database, InitialPriority will be stored as a int(11).)
963
964
965=cut
966
967
968=head2 FinalPriority
969
970Returns the current value of FinalPriority.
971(In the database, FinalPriority is stored as int(11).)
972
973
974
975=head2 SetFinalPriority VALUE
976
977
978Set FinalPriority to VALUE.
979Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
980(In the database, FinalPriority will be stored as a int(11).)
981
982
983=cut
984
985
986=head2 DefaultDueIn
987
988Returns the current value of DefaultDueIn.
989(In the database, DefaultDueIn is stored as int(11).)
990
991
992
993=head2 SetDefaultDueIn VALUE
994
995
996Set DefaultDueIn to VALUE.
997Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
998(In the database, DefaultDueIn will be stored as a int(11).)
999
1000
1001=cut
1002
1003
1004=head2 Creator
1005
1006Returns the current value of Creator.
1007(In the database, Creator is stored as int(11).)
1008
1009
1010=cut
1011
1012
1013=head2 Created
1014
1015Returns the current value of Created.
1016(In the database, Created is stored as datetime.)
1017
1018
1019=cut
1020
1021
1022=head2 LastUpdatedBy
1023
1024Returns the current value of LastUpdatedBy.
1025(In the database, LastUpdatedBy is stored as int(11).)
1026
1027
1028=cut
1029
1030
1031=head2 LastUpdated
1032
1033Returns the current value of LastUpdated.
1034(In the database, LastUpdated is stored as datetime.)
1035
1036
1037=cut
1038
1039
1040=head2 Disabled
1041
1042Returns the current value of Disabled.
1043(In the database, Disabled is stored as smallint(6).)
1044
1045
1046
1047=head2 SetDisabled VALUE
1048
1049
1050Set Disabled to VALUE.
1051Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1052(In the database, Disabled will be stored as a smallint(6).)
1053
1054
1055=cut
1056
1057
1058
1059sub _CoreAccessible {
1060 {
1061
1062 id =>
1063 {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''},
1064 Name =>
1065 {read => 1, write => 1, sql_type => 12, length => 200, is_blob => 0, is_numeric => 0, type => 'varchar(200)', default => ''},
1066 Description =>
1067 {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''},
1068 CorrespondAddress =>
1069 {read => 1, write => 1, sql_type => 12, length => 120, is_blob => 0, is_numeric => 0, type => 'varchar(120)', default => ''},
1070 CommentAddress =>
1071 {read => 1, write => 1, sql_type => 12, length => 120, is_blob => 0, is_numeric => 0, type => 'varchar(120)', default => ''},
1072 SubjectTag =>
1073 {read => 1, write => 1, sql_type => 12, length => 120, is_blob => 0, is_numeric => 0, type => 'varchar(120)', default => ''},
1074 Lifecycle =>
403d7b0b 1075 {read => 1, write => 1, sql_type => 12, length => 32, is_blob => 0, is_numeric => 0, type => 'varchar(32)', default => 'default'},
84fb5b46
MKG
1076 InitialPriority =>
1077 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
1078 FinalPriority =>
1079 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
1080 DefaultDueIn =>
1081 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
1082 Creator =>
1083 {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
1084 Created =>
1085 {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''},
1086 LastUpdatedBy =>
1087 {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
1088 LastUpdated =>
1089 {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''},
1090 Disabled =>
1091 {read => 1, write => 1, sql_type => 5, length => 6, is_blob => 0, is_numeric => 1, type => 'smallint(6)', default => '0'},
1092
1093 }
1094};
1095
af59614d
MKG
1096sub FindDependencies {
1097 my $self = shift;
1098 my ($walker, $deps) = @_;
1099
1100 $self->SUPER::FindDependencies($walker, $deps);
1101
1102 # Queue role groups( Cc, AdminCc )
1103 my $objs = RT::Groups->new( $self->CurrentUser );
320f0092 1104 $objs->Limit( FIELD => 'Domain', VALUE => 'RT::Queue-Role', CASESENSITIVE => 0 );
af59614d
MKG
1105 $objs->Limit( FIELD => 'Instance', VALUE => $self->Id );
1106 $deps->Add( in => $objs );
1107
1108 # Scrips
1109 $objs = RT::Scrips->new( $self->CurrentUser );
1110 $objs->LimitToQueue( $self->id );
1111 $deps->Add( in => $objs );
1112
1113 # Templates (global ones have already been dealt with)
1114 $objs = RT::Templates->new( $self->CurrentUser );
1115 $objs->Limit( FIELD => 'Queue', VALUE => $self->Id);
1116 $deps->Add( in => $objs );
1117
1118 # Custom Fields on things _in_ this queue (CFs on the queue itself
1119 # have already been dealt with)
1120 $objs = RT::ObjectCustomFields->new( $self->CurrentUser );
1121 $objs->Limit( FIELD => 'ObjectId',
1122 OPERATOR => '=',
1123 VALUE => $self->id,
1124 ENTRYAGGREGATOR => 'OR' );
1125 $objs->Limit( FIELD => 'ObjectId',
1126 OPERATOR => '=',
1127 VALUE => 0,
1128 ENTRYAGGREGATOR => 'OR' );
1129 my $cfs = $objs->Join(
1130 ALIAS1 => 'main',
1131 FIELD1 => 'CustomField',
1132 TABLE2 => 'CustomFields',
1133 FIELD2 => 'id',
1134 );
1135 $objs->Limit( ALIAS => $cfs,
1136 FIELD => 'LookupType',
1137 OPERATOR => 'STARTSWITH',
1138 VALUE => 'RT::Queue-' );
1139 $deps->Add( in => $objs );
1140
1141 # Tickets
1142 $objs = RT::Tickets->new( $self->CurrentUser );
320f0092 1143 $objs->Limit( FIELD => "Queue", VALUE => $self->Id );
af59614d
MKG
1144 $objs->{allow_deleted_search} = 1;
1145 $deps->Add( in => $objs );
1146}
1147
1148sub PreInflate {
1149 my $class = shift;
1150 my ($importer, $uid, $data) = @_;
1151
1152 $class->SUPER::PreInflate( $importer, $uid, $data );
1153
1154 $data->{Name} = $importer->Qualify($data->{Name})
1155 if $data->{Name} ne "___Approvals";
1156
1157 return if $importer->MergeBy( "Name", $class, $uid, $data );
1158
1159 return 1;
1160}
1161
84fb5b46
MKG
1162
1163
1164RT::Base->_ImportOverlays();
1165
11661;