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