rt 4.2.14 (#13852)
[freeside.git] / rt / lib / RT / Queue.pm
index 1656903..c149238 100755 (executable)
@@ -1,4 +1,50 @@
-# $Header: /home/cvs/cvsroot/freeside/rt/lib/RT/Queue.pm,v 1.1 2002-08-12 06:17:07 ivan Exp $
+# BEGIN BPS TAGGED BLOCK {{{
+#
+# COPYRIGHT:
+#
+# This software is Copyright (c) 1996-2017 Best Practical Solutions, LLC
+#                                          <sales@bestpractical.com>
+#
+# (Except where explicitly superseded by other copyright notices)
+#
+#
+# LICENSE:
+#
+# This work is made available to you under the terms of Version 2 of
+# the GNU General Public License. A copy of that license should have
+# been provided with this software, but in any event can be snarfed
+# from www.gnu.org.
+#
+# This work is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 or visit their web page on the internet at
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+#
+#
+# CONTRIBUTION SUBMISSION POLICY:
+#
+# (The following paragraph is not intended to limit the rights granted
+# to you to modify and distribute this software under the terms of
+# the GNU General Public License and is only of importance to you if
+# you choose to contribute your changes and enhancements to the
+# community by submitting them to Best Practical Solutions, LLC.)
+#
+# By intentionally submitting any modifications, corrections or
+# derivatives to this work, or any other work intended for use with
+# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+# you are the copyright holder for those contributions and you grant
+# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
+# royalty-free, perpetual, license to use, copy, create derivative
+# works based on those contributions, and sublicense and distribute
+# those contributions and any derivatives thereof.
+#
+# END BPS TAGGED BLOCK }}}
 
 =head1 NAME
 
 
 =head1 DESCRIPTION
 
+An RT queue object.
 
 =head1 METHODS
 
-=begin testing 
-use RT::TestHarness;
+=cut
+
+
+package RT::Queue;
 
-use RT::Queue;
+use strict;
+use warnings;
+use base 'RT::Record';
+
+use Role::Basic 'with';
+with "RT::Record::Role::Lifecycle",
+     "RT::Record::Role::Links" => { -excludes => ["_AddLinksOnCreate"] },
+     "RT::Record::Role::Roles",
+     "RT::Record::Role::Rights";
+
+sub Table {'Queues'}
+
+sub LifecycleType { "ticket" }
+
+sub ModifyLinkRight { "AdminQueue" }
+
+require RT::ACE;
+RT::ACE->RegisterCacheHandler(sub {
+    my %args = (
+        Action      => "",
+        RightName   => "",
+        @_
+    );
+
+    return unless $args{Action}    =~ /^(Grant|Revoke)$/i
+              and $args{RightName} =~ /^(SeeQueue|CreateTicket)$/;
+
+    RT->System->QueueCacheNeedsUpdate(1);
+});
+
+use RT::Groups;
+use RT::ACL;
+use RT::Interface::Email;
+
+__PACKAGE__->AddRight( General => SeeQueue            => 'View queue' ); # loc
+__PACKAGE__->AddRight( Admin   => AdminQueue          => 'Create, modify and delete queue' ); # loc
+__PACKAGE__->AddRight( Admin   => ShowACL             => 'Display Access Control List' ); # loc
+__PACKAGE__->AddRight( Admin   => ModifyACL           => 'Create, modify and delete Access Control List entries' ); # loc
+__PACKAGE__->AddRight( Admin   => ModifyQueueWatchers => 'Modify queue watchers' ); # loc
+__PACKAGE__->AddRight( General => SeeCustomField      => 'View custom field values' ); # loc
+__PACKAGE__->AddRight( Staff   => ModifyCustomField   => 'Modify custom field values' ); # loc
+__PACKAGE__->AddRight( Admin   => AssignCustomFields  => 'Assign and remove queue custom fields' ); # loc
+__PACKAGE__->AddRight( Admin   => ModifyTemplate      => 'Modify Scrip templates' ); # loc
+__PACKAGE__->AddRight( Admin   => ShowTemplate        => 'View Scrip templates' ); # loc
+
+__PACKAGE__->AddRight( Admin   => ModifyScrips        => 'Modify Scrips' ); # loc
+__PACKAGE__->AddRight( Admin   => ShowScrips          => 'View Scrips' ); # loc
+
+__PACKAGE__->AddRight( General => ShowTicket          => 'View ticket summaries' ); # loc
+__PACKAGE__->AddRight( Staff   => ShowTicketComments  => 'View ticket private commentary' ); # loc
+__PACKAGE__->AddRight( Staff   => ShowOutgoingEmail   => 'View exact outgoing email messages and their recipients' ); # loc
+
+__PACKAGE__->AddRight( General => Watch               => 'Sign up as a ticket Requestor or ticket or queue Cc' ); # loc
+__PACKAGE__->AddRight( Staff   => WatchAsAdminCc      => 'Sign up as a ticket or queue AdminCc' ); # loc
+__PACKAGE__->AddRight( General => CreateTicket        => 'Create tickets' ); # loc
+__PACKAGE__->AddRight( General => ReplyToTicket       => 'Reply to tickets' ); # loc
+__PACKAGE__->AddRight( General => CommentOnTicket     => 'Comment on tickets' ); # loc
+__PACKAGE__->AddRight( Staff   => OwnTicket           => 'Own tickets' ); # loc
+__PACKAGE__->AddRight( Staff   => ModifyTicket        => 'Modify tickets' ); # loc
+__PACKAGE__->AddRight( Staff   => DeleteTicket        => 'Delete tickets' ); # loc
+__PACKAGE__->AddRight( Staff   => TakeTicket          => 'Take tickets' ); # loc
+__PACKAGE__->AddRight( Staff   => StealTicket         => 'Steal tickets' ); # loc
+__PACKAGE__->AddRight( Staff   => ReassignTicket      => 'Modify ticket owner on owned tickets' ); # loc
+
+__PACKAGE__->AddRight( Staff   => ForwardMessage      => 'Forward messages outside of RT' ); # loc
+
+=head2 Create(ARGS)
+
+Arguments: ARGS is a hash of named parameters.  Valid parameters are:
+
+  Name (required)
+  Description
+  CorrespondAddress
+  CommentAddress
+  InitialPriority
+  FinalPriority
+  DefaultDueIn
+If you pass the ACL check, it creates the queue and returns its queue id.
 
-=end testing
 
 =cut
 
+sub Create {
+    my $self = shift;
+    my %args = (
+        Name              => undef,
+        Description       => '',
+        CorrespondAddress => '',
+        CommentAddress    => '',
+        Lifecycle         => 'default',
+        SubjectTag        => undef,
+        InitialPriority   => 0,
+        FinalPriority     => 0,
+        DefaultDueIn      => 0,
+        Sign              => undef,
+        SignAuto          => undef,
+        Encrypt           => undef,
+        _RecordTransaction => 1,
+        @_
+    );
+
+    unless ( $self->CurrentUser->HasRight(Right => 'AdminQueue', Object => $RT::System) )
+    {    #Check them ACLs
+        return ( 0, $self->loc("No permission to create queues") );
+    }
 
+    {
+        my ($val, $msg) = $self->_ValidateName( $args{'Name'} );
+        return ($val, $msg) unless $val;
+    }
 
-package RT::Queue;
-use RT::Record;
+    $args{'Lifecycle'} ||= 'default';
+
+    return ( 0, $self->loc('[_1] is not a valid lifecycle', $args{'Lifecycle'} ) )
+      unless $self->ValidateLifecycle( $args{'Lifecycle'} );
+
+    my %attrs = map {$_ => 1} $self->ReadableAttributes;
 
-@ISA= qw(RT::Record);
+    #TODO better input validation
+    $RT::Handle->BeginTransaction();
+    my $id = $self->SUPER::Create( map { $_ => $args{$_} } grep exists $args{$_}, keys %attrs );
+    unless ($id) {
+        $RT::Handle->Rollback();
+        return ( 0, $self->loc('Queue could not be created') );
+    }
 
-use vars (@STATUS);
+    my $create_ret = $self->_CreateRoleGroups();
+    unless ($create_ret) {
+        $RT::Handle->Rollback();
+        return ( 0, $self->loc('Queue could not be created') );
+    }
+    if ( $args{'_RecordTransaction'} ) {
+        $self->_NewTransaction( Type => "Create" );
+    }
+    $RT::Handle->Commit;
+
+    for my $attr (qw/Sign SignAuto Encrypt/) {
+        next unless defined $args{$attr};
+        my $set = "Set" . $attr;
+        my ($status, $msg) = $self->$set( $args{$attr} );
+        $RT::Logger->error("Couldn't set attribute '$attr': $msg")
+            unless $status;
+    }
 
-@STATUS = qw(new open stalled resolved dead); 
+    RT->System->QueueCacheNeedsUpdate(1);
+
+    return ( $id, $self->loc("Queue created") );
+}
 
-=head2 StatusArray
 
-Returns an array of all statuses for this queue
+
+sub Delete {
+    my $self = shift;
+    return ( 0,
+        $self->loc('Deleting this object would break referential integrity') );
+}
+
+=head2 Load
+
+Takes either a numerical id or a textual Name and loads the specified queue.
 
 =cut
 
-sub StatusArray {
+sub Load {
     my $self = shift;
-    return (@STATUS);
+
+    my $identifier = shift;
+    if ( !$identifier ) {
+        return (undef);
+    }
+
+    if ( $identifier =~ /^(\d+)$/ ) {
+        $self->SUPER::LoadById($identifier);
+    }
+    else {
+        $self->LoadByCols( Name => $identifier );
+    }
+
+    return ( $self->Id );
+
 }
 
 
-=head2 IsValidStatus VALUE
 
-Returns true if VALUE is a valid status.  Otherwise, returns 0
+=head2 ValidateName NAME
 
-=for testing
-my $q = new RT::Queue($RT::SystemUser);
-ok($q->IsValidStatus('new')== 1, 'New is a valid status');
-ok($q->IsValidStatus('f00')== 0, 'f00 is not a valid status');
+Takes a queue name. Returns true if it's an ok name for
+a new queue. Returns undef if there's already a queue by that name.
 
 =cut
 
-sub IsValidStatus {
-       my $self = shift;
-       my $value = shift;
+sub ValidateName {
+    my $self = shift;
+    my $name = shift;
 
-       my $retval = grep (/^$value$/, $self->StatusArray);
-       return ($retval);       
+    my ($ok, $msg) = $self->_ValidateName($name);
 
+    return $ok ? 1 : 0;
 }
-       
 
+sub _ValidateName {
+    my $self = shift;
+    my $name = shift;
 
+    return (undef, "Queue name is required") unless length $name;
 
-# {{{  sub _Init 
-sub _Init  {
-    my $self = shift;
-    $self->{'table'} = "Queues";
-    return ($self->SUPER::_Init(@_));
+    # Validate via the superclass first
+    # Case: short circuit if it's an integer so we don't have
+    # fale negatives when loading a temp queue
+    unless ( my $q = $self->SUPER::ValidateName($name) ) {
+        return ($q, $self->loc("'[_1]' is not a valid name.", $name));
+    }
+
+    my $tempqueue = RT::Queue->new(RT->SystemUser);
+    $tempqueue->Load($name);
+
+    #If this queue exists, return undef
+    if ( $tempqueue->Name() && $tempqueue->id != $self->id)  {
+        return (undef, $self->loc("Queue already exists") );
+    }
+
+    return (1);
 }
-# }}}
 
-# {{{ sub _Accessible 
 
-sub _Accessible  {
-    my $self = shift;
-    my %Cols = ( Name => 'read/write',
-                CorrespondAddress => 'read/write',
-                Description => 'read/write',
-                CommentAddress =>  'read/write',
-                InitialPriority =>  'read/write',
-                FinalPriority =>  'read/write',
-                DefaultDueIn =>  'read/write',
-                Creator => 'read/auto',
-                Created => 'read/auto',
-                LastUpdatedBy => 'read/auto',
-                LastUpdated => 'read/auto',
-                Disabled => 'read/write',
-                
-              );
-    return($self->SUPER::_Accessible(@_, %Cols));
-}
-
-# }}}
-
-# {{{ sub Create
-
-=head2 Create
-
-Create takes the name of the new queue 
-If you pass the ACL check, it creates the queue and returns its queue id.
+=head2 SetSign
 
 =cut
 
-sub Create  {
+sub Sign {
     my $self = shift;
-    my %args = ( Name => undef,
-                CorrespondAddress => '',
-                Description => '',
-                CommentAddress => '',
-                InitialPriority => "0",
-                FinalPriority =>  "0",
-                DefaultDueIn =>  "0",
-                @_); 
-    
-    unless ($self->CurrentUser->HasSystemRight('AdminQueue')) {    #Check them ACLs
-       return (0, "No permission to create queues") 
-    }
+    my $value = shift;
 
-    unless ($self->ValidateName($args{'Name'})) {
-       return(0, 'Queue already exists');
-    }
-    #TODO better input validation
-    
-    my $id = $self->SUPER::Create(%args);
-    unless ($id) {
-       return (0, 'Queue could not be created');
-    }
+    return undef unless $self->CurrentUserHasRight('SeeQueue');
+    my $attr = $self->FirstAttribute('Sign') or return 0;
+    return $attr->Content;
+}
+
+sub SetSign {
+    my $self = shift;
+    my $value = shift;
 
-    return ($id, "Queue $id created");
+    return ( 0, $self->loc('Permission Denied') )
+        unless $self->CurrentUserHasRight('AdminQueue');
+
+    my ($status, $msg) = $self->SetAttribute(
+        Name        => 'Sign',
+        Description => 'Sign outgoing messages by default',
+        Content     => $value,
+    );
+    return ($status, $msg) unless $status;
+
+    my ( undef, undef, $TransObj ) = $self->_NewTransaction(
+        Field => 'Signing', #loc
+        Type  => $value ? "Enabled" : "Disabled"
+    );
+
+    return ($status, scalar $TransObj->BriefDescription);
 }
 
-# }}}
+sub SignAuto {
+    my $self = shift;
+    my $value = shift;
 
-# {{{ sub Delete 
+    return undef unless $self->CurrentUserHasRight('SeeQueue');
+    my $attr = $self->FirstAttribute('SignAuto') or return 0;
+    return $attr->Content;
+}
 
-sub Delete {
+sub SetSignAuto {
     my $self = shift;
-    return (0, 'Deleting this object would break referential integrity');
+    my $value = shift;
+
+    return ( 0, $self->loc('Permission Denied') )
+        unless $self->CurrentUserHasRight('AdminQueue');
+
+    my ($status, $msg) = $self->SetAttribute(
+        Name        => 'SignAuto',
+        Description => 'Sign auto-generated outgoing messages',
+        Content     => $value,
+    );
+    return ($status, $msg) unless $status;
+
+    my ( undef, undef, $TransObj ) = $self->_NewTransaction(
+        Field => 'AutoSigning', #loc
+        Type  => $value ? "Enabled" : "Disabled"
+    );
+
+    return ($status, scalar $TransObj->BriefDescription);
 }
 
-# }}}
+sub Encrypt {
+    my $self = shift;
+    my $value = shift;
 
-# {{{ sub SetDisabled
+    return undef unless $self->CurrentUserHasRight('SeeQueue');
+    my $attr = $self->FirstAttribute('Encrypt') or return 0;
+    return $attr->Content;
+}
 
-=head2 SetDisabled
+sub SetEncrypt {
+    my $self = shift;
+    my $value = shift;
 
-Takes a boolean.
-1 will cause this queue to no longer be avaialble for tickets.
-0 will re-enable this queue
+    return ( 0, $self->loc('Permission Denied') )
+        unless $self->CurrentUserHasRight('AdminQueue');
 
-=cut
+    my ($status, $msg) = $self->SetAttribute(
+        Name        => 'Encrypt',
+        Description => 'Encrypt outgoing messages by default',
+        Content     => $value,
+    );
+    return ($status, $msg) unless $status;
 
-# }}}
+    my ( undef, undef, $TransObj ) = $self->_NewTransaction(
+        Field => 'Encrypting', #loc
+        Type  => $value ? "Enabled" : "Disabled"
+    );
 
-# {{{ sub Load 
+    return ($status, scalar $TransObj->BriefDescription);
+}
 
-=head2 Load
+=head2 Templates
+
+Returns an RT::Templates object of all of this queue's templates.
 
-Takes either a numerical id or a textual Name and loads the specified queue.
-  
 =cut
 
-sub Load  {
+sub Templates {
     my $self = shift;
-    
-    my $identifier = shift;
-    if (!$identifier) {
-       return (undef);
-    }      
-    
-    if ($identifier !~ /\D/) {
-       $self->SUPER::LoadById($identifier);
-    }
-    else {
-       $self->LoadByCol("Name", $identifier);
-    }
 
-    return ($self->Id);
+    my $templates = RT::Templates->new( $self->CurrentUser );
 
+    if ( $self->CurrentUserHasRight('ShowTemplate') ) {
+        $templates->LimitToQueue( $self->id );
+    }
 
+    return ($templates);
 }
-# }}}
 
-# {{{ sub ValidateName
 
-=head2 ValidateName NAME
 
-Takes a queue name. Returns true if it's an ok name for
-a new queue. Returns undef if there's already a queue by that name.
+
+=head2 CustomField NAME
+
+Load the Ticket Custom Field applied to this Queue named NAME.
+Does not load Global custom fields.
 
 =cut
 
-sub ValidateName {
+sub CustomField {
     my $self = shift;
     my $name = shift;
-   
-    my $tempqueue = new RT::Queue($RT::SystemUser);
-    $tempqueue->Load($name);
+    my $cf = RT::CustomField->new($self->CurrentUser);
+    $cf->LoadByName(
+        Name       => $name,
+        LookupType => RT::Ticket->CustomFieldLookupType,
+        ObjectId   => $self->id,
+    );
+    return ($cf);
+}
 
-    #If we couldn't load it :)
-    unless ($tempqueue->id()) {
-       return(1);
-    }
 
-    #If this queue exists, return undef
-    #Avoid the ACL check.
-    if ($tempqueue->Name()){
-        return(undef);
-    }
 
-    #If the queue doesn't exist, return 1
-    else {
-        return(1);
+=head2 TicketCustomFields
+
+Returns an L<RT::CustomFields> object containing all global and
+queue-specific B<ticket> custom fields.
+
+=cut
+
+sub TicketCustomFields {
+    my $self = shift;
+
+    my $cfs = RT::CustomFields->new( $self->CurrentUser );
+    if ( $self->CurrentUserHasRight('SeeQueue') ) {
+        $cfs->SetContextObject( $self );
+        $cfs->LimitToGlobalOrObjectId( $self->Id );
+        $cfs->LimitToLookupType( 'RT::Queue-RT::Ticket' );
+        $cfs->ApplySortOrder;
     }
+    return ($cfs);
+}
+
+
+
+=head2 TicketTransactionCustomFields
+
+Returns an L<RT::CustomFields> object containing all global and
+queue-specific B<transaction> custom fields.
+
+=cut
 
+sub TicketTransactionCustomFields {
+    my $self = shift;
+
+    my $cfs = RT::CustomFields->new( $self->CurrentUser );
+    if ( $self->CurrentUserHasRight('SeeQueue') ) {
+        $cfs->SetContextObject( $self );
+        $cfs->LimitToGlobalOrObjectId( $self->Id );
+        $cfs->LimitToLookupType( 'RT::Queue-RT::Ticket-RT::Transaction' );
+        $cfs->ApplySortOrder;
+    }
+    return ($cfs);
 }
 
 
-# }}}
 
-# {{{ sub Templates
 
-=head2 Templates
 
-Returns an RT::Templates object of all of this queue's templates.
+=head2 AllRoleGroupTypes
+
+B<DEPRECATED> and will be removed in a future release. Use L</Roles>
+instead.
+
+Returns a list of the names of the various role group types for Queues,
+including roles used only for ACLs like Requestor and Owner. If you don't want
+them, see L</ManageableRoleGroupTypes>.
 
 =cut
 
-sub Templates {
-    my $self = shift;
-    
+sub AllRoleGroupTypes {
+    RT->Deprecated(
+        Remove => "4.4",
+        Instead => "RT::Queue->Roles",
+    );
+    shift->Roles;
+}
 
-    my $templates = RT::Templates->new($self->CurrentUser);
+=head2 IsRoleGroupType
 
-    if ($self->CurrentUserHasRight('ShowTemplate')) {
-       $templates->LimitToQueue($self->id);
-    }
-    
-    return ($templates); 
+B<DEPRECATED> and will be removed in a future release. Use L</HasRole> instead.
+
+Returns whether the passed-in type is a role group type.
+
+=cut
+
+sub IsRoleGroupType {
+    RT->Deprecated(
+        Remove => "4.4",
+        Instead => "RT::Queue->HasRole",
+    );
+    shift->HasRole(@_);
 }
 
-# }}}
+=head2 ManageableRoleGroupTypes
 
-# {{{ Dealing with watchers
+Returns a list of the names of the various role group types for Queues,
+excluding ones used only for ACLs such as Requestor and Owner. If you want
+them, see L</Roles>.
 
-# {{{ sub Watchers
+=cut
 
-=head2 Watchers
+sub ManageableRoleGroupTypes {
+    shift->Roles( ACLOnly => 0 )
+}
 
-Watchers returns a Watchers object preloaded with this queue\'s watchers.
+=head2 IsManageableRoleGroupType
+
+Returns whether the passed-in type is a manageable role group type.
 
 =cut
 
-sub Watchers {
+sub IsManageableRoleGroupType {
     my $self = shift;
-    
-    require RT::Watchers;
-    my $watchers =RT::Watchers->new($self->CurrentUser);
-    
-    if ($self->CurrentUserHasRight('SeeQueue')) {
-       $watchers->LimitToQueue($self->id);     
-    }  
-    
-    return($watchers);
+    my $type = shift;
+    return( $self->HasRole($type) and not $self->Role($type)->{ACLOnly} );
+}
+
+
+sub _HasModifyWatcherRight {
+    my $self = shift;
+    my ($type, $principal) = @_;
+
+    # ModifyQueueWatchers works in any case
+    return 1 if $self->CurrentUserHasRight('ModifyQueueWatchers');
+    # If the watcher isn't the current user then the current user has no right
+    return 0 unless $self->CurrentUser->PrincipalId == $principal->id;
+    # If it's an AdminCc and they don't have 'WatchAsAdminCc', bail
+    return 0 if $type eq 'AdminCc' and not $self->CurrentUserHasRight('WatchAsAdminCc');
+    # If it's a Requestor or Cc and they don't have 'Watch', bail
+    return 0 if ($type eq "Cc" or $type eq 'Requestor')
+        and not $self->CurrentUserHasRight('Watch');
+    return 1;
 }
 
-# }}}
 
-# {{{ sub WatchersAsString
-=head2 WatchersAsString
+=head2 AddWatcher
+
+Applies access control checking, then calls
+L<RT::Record::Role::Roles/AddRoleMember>.  Additionally, C<Email> is
+accepted as an alternative argument name for C<User>.
 
-Returns a string of all queue watchers email addresses concatenated with ','s.
+Returns a tuple of (status, message).
 
 =cut
 
-sub WatchersAsString {
-    my $self=shift;
-    return($self->Watchers->EmailsAsString());
+sub AddWatcher {
+    my $self = shift;
+    my %args = (
+        Type  => undef,
+        PrincipalId => undef,
+        Email => undef,
+        @_
+    );
+
+    $args{ACL} = sub { $self->_HasModifyWatcherRight( @_ ) };
+    $args{User} ||= delete $args{Email};
+    my ($principal, $msg) = $self->AddRoleMember( %args );
+    return ( 0, $msg) unless $principal;
+
+    return ( 1, $self->loc("Added [_1] to members of [_2] for this queue.",
+                           $principal->Object->Name, $self->loc($args{'Type'}) ));
 }
 
-# }}}
 
-# {{{ sub AdminCcAsString 
+=head2 DeleteWatcher
 
-=head2 AdminCcAsString
+Applies access control checking, then calls
+L<RT::Record::Role::Roles/DeleteRoleMember>.  Additionally, C<Email> is
+accepted as an alternative argument name for C<User>.
 
-Takes nothing. returns a string: All Ticket/Queue AdminCcs.
+Returns a tuple of (status, message).
 
 =cut
 
+sub DeleteWatcher {
+    my $self = shift;
 
-sub AdminCcAsString {
-    my $self=shift;
-    
-    return($self->AdminCc->EmailsAsString());
-  }
+    my %args = (
+        Type => undef,
+        PrincipalId => undef,
+        Email => undef,
+        @_
+    );
+
+    $args{ACL} = sub { $self->_HasModifyWatcherRight( @_ ) };
+    $args{User} ||= delete $args{Email};
+    my ($principal, $msg) = $self->DeleteRoleMember( %args );
+    return ( 0, $msg) unless $principal;
+
+    return ( 1, $self->loc("Removed [_1] from members of [_2] for this queue.",
+                           $principal->Object->Name, $self->loc($args{'Type'}) ));
+}
 
-# }}}
 
-# {{{ sub CcAsString
 
-=head2 CcAsString
+=head2 AdminCcAddresses
 
-B<Returns> String: All Queue Ccs as a comma delimited set of email addresses.
+returns String: All queue AdminCc email addresses as a string
 
 =cut
 
-sub CcAsString {
-    my $self=shift;
+sub AdminCcAddresses {
+    my $self = shift;
     
-    return ($self->Cc->EmailsAsString());
-}
+    unless ( $self->CurrentUserHasRight('SeeQueue') ) {
+        return undef;
+    }   
+    
+    return ( $self->AdminCc->MemberEmailAddressesAsString )
+    
+}   
 
-# }}}
 
-# {{{ sub Cc
 
-=head2 Cc
+=head2 CcAddresses
 
-Takes nothing.
-Returns a watchers object which contains this queue\'s Cc watchers
+returns String: All queue Ccs as a string of email addresses
 
 =cut
 
-sub Cc {
+sub CcAddresses {
     my $self = shift;
-    my $cc = $self->Watchers();
-    if ($self->CurrentUserHasRight('SeeQueue')) {
-       $cc->LimitToCc();
+
+    unless ( $self->CurrentUserHasRight('SeeQueue') ) {
+        return undef;
     }
-    return ($cc);
+
+    return ( $self->Cc->MemberEmailAddressesAsString);
+
 }
 
-# A helper function for Cc, so that we can call it from the ACL checks 
-# without going through acl checks.
 
-sub _Cc {
+
+=head2 Cc
+
+Takes nothing.
+Returns an RT::Group object which contains this Queue's Ccs.
+If the user doesn't have "ShowQueue" permission, returns an empty group
+
+=cut
+
+sub Cc {
     my $self = shift;
-    my $cc = $self->Watchers();
-    $cc->LimitToCc();
-    return($cc);
-    
+
+    return RT::Group->new($self->CurrentUser)
+        unless $self->CurrentUserHasRight('SeeQueue');
+    return $self->RoleGroup( 'Cc' );
 }
 
-# }}}
 
-# {{{ sub AdminCc
 
 =head2 AdminCc
 
 Takes nothing.
-Returns this queue's administrative Ccs as an RT::Watchers object
+Returns an RT::Group object which contains this Queue's AdminCcs.
+If the user doesn't have "ShowQueue" permission, returns an empty group
 
 =cut
 
 sub AdminCc {
     my $self = shift;
-    my $admin_cc = $self->Watchers();
-    if ($self->CurrentUserHasRight('SeeQueue')) {
-       $admin_cc->LimitToAdminCc();
-    }
-    return($admin_cc);
-}
 
-#helper function for AdminCc so we can call it without ACLs
-sub _AdminCc {
-    my $self = shift;
-    my $admin_cc = $self->Watchers();
-    $admin_cc->LimitToAdminCc();
-    return($admin_cc);
+    return RT::Group->new($self->CurrentUser)
+        unless $self->CurrentUserHasRight('SeeQueue');
+    return $self->RoleGroup( 'AdminCc' );
 }
 
-# }}}
-
-# {{{ IsWatcher, IsCc, IsAdminCc
 
-# {{{ sub IsWatcher
 
 # a generic routine to be called by IsRequestor, IsCc and IsAdminCc
 
-=head2 IsWatcher
+=head2 IsWatcher { Type => TYPE, PrincipalId => PRINCIPAL_ID }
+
+Takes a param hash with the attributes Type and PrincipalId
+
+Type is one of Requestor, Cc, AdminCc and Owner
+
+PrincipalId is an RT::Principal id 
+
+Returns true if that principal is a member of the group Type for this queue
 
-Takes a param hash with the attributes Type and User. User is either a user object or string containing an email address. Returns true if that user or string
-is a queue watcher. Returns undef otherwise
 
 =cut
 
 sub IsWatcher {
     my $self = shift;
-    
-    my %args = ( Type => 'Requestor',
-                Id => undef,
-                Email => undef,
-                @_
-              );
-    #ACL check - can't do it. we need this method for ACL checks
-    #    unless ($self->CurrentUserHasRight('SeeQueue')) {
-    #  return(undef);
-    #    }
-
-
-    my %cols = ('Type' => $args{'Type'},
-               'Scope' => 'Queue',
-               'Value' => $self->Id
-              );
-    if (defined ($args{'Id'})) {
-       if (ref($args{'Id'})){ #If it's a ref, assume it's an RT::User object;
-           #Dangerous but ok for now
-           $cols{'Owner'} = $args{'Id'}->Id;
-       }
-       elsif ($args{'Id'} =~ /^\d+$/) { # if it's an integer, it's an RT::User obj
-           $cols{'Owner'} = $args{'Id'};
-       }
-       else {
-           $cols{'Email'} = $args{'Id'};
-       }       
-    }  
-    
-    if (defined $args{'Email'}) {
-       $cols{'Email'} = $args{'Email'};
-    }
 
-    my ($description);
-    $description = join(":",%cols);
-    
-    #If we've cached a positive match...
-    if (defined $self->{'watchers_cache'}->{"$description"}) {
-       if ($self->{'watchers_cache'}->{"$description"} == 1) {
-           return(1);
-       }
-       #If we've cached a negative match...
-       else {
-           return(undef);
-       }
-    }
+    my %args = ( Type  => 'Cc',
+        PrincipalId    => undef,
+        @_
+    );
 
-    require RT::Watcher;
-    my $watcher = new RT::Watcher($self->CurrentUser);
-    $watcher->LoadByCols(%cols);
-    
-    
-    if ($watcher->id) {
-       $self->{'watchers_cache'}->{"$description"} = 1;
-       return(1);
-    }  
-    else {
-       $self->{'watchers_cache'}->{"$description"} = 0;
-       return(undef);
+    # Load the relevant group.
+    my $group = $self->RoleGroup( $args{'Type'} );
+    # Ask if it has the member in question
+
+    my $principal = RT::Principal->new($self->CurrentUser);
+    $principal->Load($args{'PrincipalId'});
+    unless ($principal->Id) {
+        return (undef);
     }
-    
+
+    return ($group->HasMemberRecursively($principal));
 }
 
-# }}}
 
-# {{{ sub IsCc
 
-=head2 IsCc
 
-Takes a string. Returns true if the string is a Cc watcher of the current queue
+=head2 IsCc PRINCIPAL_ID
 
-=item Bugs
+Takes an RT::Principal id.
+Returns true if the principal is a requestor of the current queue.
 
-Should also be able to handle an RT::User object
 
 =cut
 
-
 sub IsCc {
-  my $self = shift;
-  my $cc = shift;
-  
-  return ($self->IsWatcher( Type => 'Cc', Id => $cc ));
-  
-}
+    my $self = shift;
+    my $cc   = shift;
 
-# }}}
+    return ( $self->IsWatcher( Type => 'Cc', PrincipalId => $cc ) );
 
-# {{{ sub IsAdminCc
+}
 
-=head2 IsAdminCc
 
-Takes a string. Returns true if the string is an AdminCc watcher of the current queue
 
-=item Bugs
+=head2 IsAdminCc PRINCIPAL_ID
 
-Should also be able to handle an RT::User object
+Takes an RT::Principal id.
+Returns true if the principal is a requestor of the current queue.
 
 =cut
 
 sub IsAdminCc {
-  my $self = shift;
-  my $admincc = shift;
-  
-  return ($self->IsWatcher( Type => 'AdminCc', Id => $admincc ));
-  
+    my $self   = shift;
+    my $person = shift;
+
+    return ( $self->IsWatcher( Type => 'AdminCc', PrincipalId => $person ) );
+
 }
 
-# }}}
 
-# }}}
 
-# {{{ sub AddWatcher
 
-=head2 AddWatcher
 
-Takes a paramhash of Email, Owner and Type. Type is one of 'Cc' or 'AdminCc',
-We need either an Email Address in Email or a userid in Owner
 
-=cut
 
-sub AddWatcher {
+
+
+
+sub _Set {
     my $self = shift;
-    my %args = ( Email => undef,
-                Type => undef,
-                Owner => 0,
-                @_
-              );
-    
-    # {{{ Check ACLS
-    #If the watcher we're trying to add is for the current user
-    if ( ( ( defined $args{'Email'})  && 
-           ( $args{'Email'} eq $self->CurrentUser->EmailAddress) ) or 
-        ($args{'Owner'} eq $self->CurrentUser->Id)) {
-       
-       #  If it's an AdminCc and they don't have 
-       #   'WatchAsAdminCc' or 'ModifyQueueWatchers', bail
-       if ($args{'Type'} eq 'AdminCc') {
-           unless ($self->CurrentUserHasRight('ModifyQueueWatchers') or 
-                   $self->CurrentUserHasRight('WatchAsAdminCc')) {
-               return(0, 'Permission Denied');
-           }
-       }
-
-       #  If it's a Requestor or Cc and they don't have
-       #   'Watch' or 'ModifyQueueWatchers', bail
-       elsif ($args{'Type'} eq 'Cc') {
-           unless ($self->CurrentUserHasRight('ModifyQueueWatchers') or 
-                   $self->CurrentUserHasRight('Watch')) {
-               return(0, 'Permission Denied');
-           }
-       }
-       else {
-           $RT::Logger->warn("$self -> AddWatcher hit code".
-                             " it never should. We got passed ".
-                             " a type of ". $args{'Type'});
-           return (0,'Error in parameters to $self AddWatcher');
-       }
+
+    my %args = (
+        Field             => undef,
+        Value             => undef,
+        TransactionType   => 'Set',
+        RecordTransaction => 1,
+        @_
+    );
+
+    unless ( $self->CurrentUserHasRight('AdminQueue') ) {
+        return ( 0, $self->loc('Permission Denied') );
     }
-    # If the watcher isn't the current user 
-    # and the current user  doesn't have 'ModifyQueueWatchers'
-    # bail
-    else {
-       unless ($self->CurrentUserHasRight('ModifyQueueWatchers')) {
-           return (0, "Permission Denied");
-       }
+
+    my $Old = $self->SUPER::_Value("$args{'Field'}");
+
+    my ($ret, $msg) = $self->SUPER::_Set(
+        Field => $args{'Field'},
+        Value => $args{'Value'},
+    );
+
+    if ( $ret == 0 ) { return ( 0, $msg ); }
+
+    RT->System->QueueCacheNeedsUpdate(1);
+
+    if ( $args{'RecordTransaction'} == 1 ) {
+        if ($args{'Field'} eq 'Disabled') {
+            $args{'TransactionType'} = ($args{'Value'} == 1) ? "Disabled" : "Enabled";
+            delete $args{'Field'};
+        }
+        my ( undef, undef, $TransObj ) = $self->_NewTransaction(
+            Type      => $args{'TransactionType'},
+            Field     => $args{'Field'},
+            NewValue  => $args{'Value'},
+            OldValue  => $Old,
+            TimeTaken => $args{'TimeTaken'},
+        );
     }
-    # }}}
-        
-    require RT::Watcher;
-    my $Watcher = new RT::Watcher ($self->CurrentUser);
-    return ($Watcher->Create(Scope => 'Queue', 
-                            Value => $self->Id,
-                            Email => $args{'Email'},
-                            Type => $args{'Type'},
-                            Owner => $args{'Owner'}
-                           ));
+
+    return ( $ret, $msg );
 }
 
-# }}}
 
-# {{{ sub AddCc
 
-=head2 AddCc
+sub _Value {
+    my $self = shift;
 
-Add a Cc to this queue.
-Takes a paramhash of Email and Owner. 
-We need either an Email Address in Email or a userid in Owner
+    unless ( $self->CurrentUserHasRight('SeeQueue') ) {
+        return (undef);
+    }
 
-=cut
+    return ( $self->__Value(@_) );
+}
 
+=head2 CurrentUserCanSee
 
-sub AddCc {
+Returns true if the current user can see the queue, using SeeQueue
+
+=cut
+
+sub CurrentUserCanSee {
     my $self = shift;
-    return ($self->AddWatcher( Type => 'Cc', @_));
+
+    return $self->CurrentUserHasRight('SeeQueue');
 }
-# }}}
 
-# {{{ sub AddAdminCc
+=head2 id
 
-=head2 AddAdminCc
+Returns the current value of id. 
+(In the database, id is stored as int(11).)
 
-Add an Administrative Cc to this queue.
-Takes a paramhash of Email and Owner. 
-We need either an Email Address in Email or a userid in Owner
 
 =cut
 
-sub AddAdminCc {
-    my $self = shift;
-    return ($self->AddWatcher( Type => 'AdminCc', @_));
-}
-# }}}
 
-# {{{ sub DeleteWatcher
+=head2 Name
+
+Returns the current value of Name. 
+(In the database, Name is stored as varchar(200).)
+
+
+
+=head2 SetName VALUE
 
-=head2 DeleteWatcher id [type]
 
-DeleteWatcher takes a single argument which is either an email address 
-or a watcher id.  
-If the first argument is an email address, you need to specify the watcher type you're talking
-about as the second argument. Valid values are 'Cc' or 'AdminCc'.
-It removes that watcher from this Queue\'s list of watchers.
+Set Name to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, Name will be stored as a varchar(200).)
 
 
 =cut
 
 
-sub DeleteWatcher {
-    my $self = shift;
-    my $id = shift;
-    
-    my $type;
-    
-    $type = shift if (@_);
-    
+=head2 Description
 
-    require RT::Watcher;
-    my $Watcher = new RT::Watcher($self->CurrentUser);
-    
-    #If it\'s a numeric watcherid
-    if ($id =~ /^(\d*)$/) {
-       $Watcher->Load($id);
-    }
-    
-    #Otherwise, we'll assume it's an email address
-    elsif ($type) {
-       my ($result, $msg) = 
-         $Watcher->LoadByValue( Email => $id,
-                                Scope => 'Queue',
-                                Value => $self->id,
-                                Type => $type);
-       return (0,$msg) unless ($result);
-    }
-    
-    else {
-       return(0,"Can\'t delete a watcher by email address without specifying a type");
-    }
-    
-    # {{{ Check ACLS 
-
-    #If the watcher we're trying to delete is for the current user
-    if ($Watcher->Email eq $self->CurrentUser->EmailAddress) {
-               
-       #  If it's an AdminCc and they don't have 
-       #   'WatchAsAdminCc' or 'ModifyQueueWatchers', bail
-       if ($Watcher->Type eq 'AdminCc') {
-           unless ($self->CurrentUserHasRight('ModifyQueueWatchers') or 
-                   $self->CurrentUserHasRight('WatchAsAdminCc')) {
-               return(0, 'Permission Denied');
-           }
-       }
-
-       #  If it's a  Cc and they don't have
-       #   'Watch' or 'ModifyQueueWatchers', bail
-       elsif ($Watcher->Type eq 'Cc') {
-           unless ($self->CurrentUserHasRight('ModifyQueueWatchers') or 
-                   $self->CurrentUserHasRight('Watch')) {
-               return(0, 'Permission Denied');
-           }
-       }
-       else {
-           $RT::Logger->warn("$self -> DeleteWatcher hit code".
-                             " it never should. We got passed ".
-                             " a type of ". $args{'Type'});
-           return (0,'Error in parameters to $self DeleteWatcher');
-       }
-    }
-    # If the watcher isn't the current user 
-    # and the current user  doesn't have 'ModifyQueueWatchers'
-    # bail
-    else {
-       unless ($self->CurrentUserHasRight('ModifyQueueWatchers')) {
-           return (0, "Permission Denied");
-       }
-    }
+Returns the current value of Description. 
+(In the database, Description is stored as varchar(255).)
 
-    # }}}
-    
-    unless (($Watcher->Scope eq 'Queue') and
-           ($Watcher->Value == $self->id) ) {
-       return (0, "Not a watcher for this queue");
-    }
-    
 
-    #Clear out the watchers hash.
-    $self->{'watchers'} = undef;
-    
-    my $retval = $Watcher->Delete();
-    
-    unless ($retval) {
-       return(0,"Watcher could not be deleted.");
-    }
-    
-    return(1, "Watcher deleted");
-}
 
-# {{{ sub DeleteCc
+=head2 SetDescription VALUE
 
-=head2 DeleteCc EMAIL
 
-Takes an email address. It calls DeleteWatcher with a preset 
-type of 'Cc'
+Set Description to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, Description will be stored as a varchar(255).)
 
 
 =cut
 
-sub DeleteCc {
-   my $self = shift;
-   my $id = shift;
-   return ($self->DeleteWatcher ($id, 'Cc'))
-}
 
-# }}}
+=head2 CorrespondAddress
+
+Returns the current value of CorrespondAddress. 
+(In the database, CorrespondAddress is stored as varchar(120).)
+
 
-# {{{ sub DeleteAdminCc
 
-=head2 DeleteAdminCc EMAIL
+=head2 SetCorrespondAddress VALUE
 
-Takes an email address. It calls DeleteWatcher with a preset 
-type of 'AdminCc'
+
+Set CorrespondAddress to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, CorrespondAddress will be stored as a varchar(120).)
 
 
 =cut
 
-sub DeleteAdminCc {
-   my $self = shift;
-   my $id = shift;
-   return ($self->DeleteWatcher ($id, 'AdminCc'))
-}
 
-# }}}
+=head2 CommentAddress
 
+Returns the current value of CommentAddress. 
+(In the database, CommentAddress is stored as varchar(120).)
 
-# }}}
 
-# }}}
 
-# {{{ Dealing with keyword selects
+=head2 SetCommentAddress VALUE
 
-# {{{ sub AddKeywordSelect
 
-=head2 AddKeywordSelect
+Set CommentAddress to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, CommentAddress will be stored as a varchar(120).)
 
-Takes a paramhash of Name, Keyword, Depth and Single.  Adds a new KeywordSelect for 
-this queue with those attributes.
 
 =cut
 
 
-sub AddKeywordSelect {
-    my $self = shift;
-    my %args = ( Keyword => undef,
-                Depth => undef,
-                Single => undef,
-                Name => undef,
-                @_);
-    
-    #ACLS get handled in KeywordSelect
-    my $NewKeywordSelect = new RT::KeywordSelect($self->CurrentUser);
-    
-    return ($NewKeywordSelect->Create (Keyword => $args{'Keyword'},
-                              Depth => $args{'Depth'},
-                              Name => $args{'Name'},
-                              Single => $args{'Single'},
-                              ObjectType => 'Ticket',
-                              ObjectField => 'Queue',
-                              ObjectValue => $self->Id()
-                             ) );
-}
+=head2 Lifecycle
+
+Returns the current value of Lifecycle. 
+(In the database, Lifecycle is stored as varchar(32).)
+
 
-# }}}
 
-# {{{ sub KeywordSelect
+=head2 SetLifecycle VALUE
 
-=head2 KeywordSelect([NAME])
 
-Takes the name of a keyword select for this queue or that's global.
-Returns the relevant KeywordSelect object.  Prefers a keywordselect that's 
-specific to this queue over a global one.  If it can't find the proper
-Keword select or the user doesn't have permission, returns an empty 
-KeywordSelect object
+Set Lifecycle to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, Lifecycle will be stored as a varchar(32).)
+
 
 =cut
 
-sub KeywordSelect {
-    my $self = shift;
-    my $name = shift;
-    
-    require RT::KeywordSelect;
+=head2 SubjectTag
+
+Returns the current value of SubjectTag. 
+(In the database, SubjectTag is stored as varchar(120).)
 
-    my $select = RT::KeywordSelect->new($self->CurrentUser);
-    if ($self->CurrentUserHasRight('SeeQueue')) {
-       $select->LoadByName( Name => $name, Queue => $self->Id);
-    }
-    return ($select);
-}
 
 
-# }}}
+=head2 SetSubjectTag VALUE
 
-# {{{ sub KeywordSelects
 
-=head2 KeywordSelects
+Set SubjectTag to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, SubjectTag will be stored as a varchar(120).)
 
-Returns an B<RT::KeywordSelects> object containing the collection of
-B<RT::KeywordSelect> objects which apply to this queue. (Both queue specific keyword selects
-and global keyword selects.
 
 =cut
 
-sub KeywordSelects {
-  my $self = shift;
 
+=head2 InitialPriority
 
-  use RT::KeywordSelects;
-  my $KeywordSelects = new RT::KeywordSelects($self->CurrentUser);
+Returns the current value of InitialPriority. 
+(In the database, InitialPriority is stored as int(11).)
 
-  if ($self->CurrentUserHasRight('SeeQueue')) {
-      $KeywordSelects->LimitToQueue($self->id);
-      $KeywordSelects->IncludeGlobals();
-  }
-  return ($KeywordSelects);
-}
-# }}}
 
-# }}}
 
-# {{{ ACCESS CONTROL
+=head2 SetInitialPriority VALUE
 
-# {{{ sub ACL 
 
-=head2 ACL
+Set InitialPriority to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, InitialPriority will be stored as a int(11).)
 
-#Returns an RT::ACL object of ACEs everyone who has anything to do with this queue.
 
 =cut
 
-sub ACL  {
-    my $self = shift;
-    
-    use RT::ACL;
-    my $acl = new RT::ACL($self->CurrentUser);
-    
-    if ($self->CurrentUserHasRight('ShowACL')) {
-       $acl->LimitToQueue($self->Id);
-    }
-    
-    return ($acl);
-}
 
-# }}}
+=head2 FinalPriority
 
-# {{{ sub _Set
-sub _Set {
-    my $self = shift;
+Returns the current value of FinalPriority. 
+(In the database, FinalPriority is stored as int(11).)
 
-    unless ($self->CurrentUserHasRight('AdminQueue')) {
-       return(0, 'Permission Denied');
-    }  
-    return ($self->SUPER::_Set(@_));
-}
-# }}}
 
-# {{{ sub _Value
 
-sub _Value {
-    my $self = shift;
+=head2 SetFinalPriority VALUE
 
-    unless ($self->CurrentUserHasRight('SeeQueue')) {
-       return (undef);
-    }
 
-    return ($self->__Value(@_));
-}
+Set FinalPriority to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, FinalPriority will be stored as a int(11).)
+
+
+=cut
+
+
+=head2 DefaultDueIn
+
+Returns the current value of DefaultDueIn. 
+(In the database, DefaultDueIn is stored as int(11).)
+
 
-# }}}
 
-# {{{ sub CurrentUserHasRight
+=head2 SetDefaultDueIn VALUE
 
-=head2 CurrentUserHasRight
 
-Takes one argument. A textual string with the name of the right we want to check.
-Returns true if the current user has that right for this queue.
-Returns undef otherwise.
+Set DefaultDueIn to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, DefaultDueIn will be stored as a int(11).)
+
 
 =cut
 
-sub CurrentUserHasRight {
-  my $self = shift;
-  my $right = shift;
 
-  return ($self->HasRight( Principal=> $self->CurrentUser,
-                            Right => "$right"));
+=head2 Creator
+
+Returns the current value of Creator. 
+(In the database, Creator is stored as int(11).)
+
+
+=cut
+
+
+=head2 Created
+
+Returns the current value of Created. 
+(In the database, Created is stored as datetime.)
+
+
+=cut
+
+
+=head2 LastUpdatedBy
+
+Returns the current value of LastUpdatedBy. 
+(In the database, LastUpdatedBy is stored as int(11).)
+
+
+=cut
+
+
+=head2 LastUpdated
+
+Returns the current value of LastUpdated. 
+(In the database, LastUpdated is stored as datetime.)
+
+
+=cut
+
+
+=head2 Disabled
+
+Returns the current value of Disabled. 
+(In the database, Disabled is stored as smallint(6).)
 
-}
 
-# }}}
 
-# {{{ sub HasRight
+=head2 SetDisabled VALUE
 
-=head2 HasRight
 
-Takes a param hash with the fields 'Right' and 'Principal'.
-Principal defaults to the current user.
-Returns true if the principal has that right for this queue.
-Returns undef otherwise.
+Set Disabled to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, Disabled will be stored as a smallint(6).)
+
 
 =cut
 
-# TAKES: Right and optional "Principal" which defaults to the current user
-sub HasRight {
+
+
+sub _CoreAccessible {
+    {
+     
+        id =>
+        {read => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => ''},
+        Name => 
+        {read => 1, write => 1, sql_type => 12, length => 200,  is_blob => 0,  is_numeric => 0,  type => 'varchar(200)', default => ''},
+        Description => 
+        {read => 1, write => 1, sql_type => 12, length => 255,  is_blob => 0,  is_numeric => 0,  type => 'varchar(255)', default => ''},
+        CorrespondAddress => 
+        {read => 1, write => 1, sql_type => 12, length => 120,  is_blob => 0,  is_numeric => 0,  type => 'varchar(120)', default => ''},
+        CommentAddress => 
+        {read => 1, write => 1, sql_type => 12, length => 120,  is_blob => 0,  is_numeric => 0,  type => 'varchar(120)', default => ''},
+        SubjectTag => 
+        {read => 1, write => 1, sql_type => 12, length => 120,  is_blob => 0,  is_numeric => 0,  type => 'varchar(120)', default => ''},
+        Lifecycle => 
+        {read => 1, write => 1, sql_type => 12, length => 32,  is_blob => 0, is_numeric => 0,  type => 'varchar(32)', default => 'default'},
+        InitialPriority => 
+        {read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
+        FinalPriority => 
+        {read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
+        DefaultDueIn => 
+        {read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
+        Creator => 
+        {read => 1, auto => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
+        Created => 
+        {read => 1, auto => 1, sql_type => 11, length => 0,  is_blob => 0,  is_numeric => 0,  type => 'datetime', default => ''},
+        LastUpdatedBy => 
+        {read => 1, auto => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
+        LastUpdated => 
+        {read => 1, auto => 1, sql_type => 11, length => 0,  is_blob => 0,  is_numeric => 0,  type => 'datetime', default => ''},
+        Disabled => 
+        {read => 1, write => 1, sql_type => 5, length => 6,  is_blob => 0,  is_numeric => 1,  type => 'smallint(6)', default => '0'},
+
+ }
+};
+
+sub FindDependencies {
     my $self = shift;
-        my %args = ( Right => undef,
-                     Principal => $self->CurrentUser,
-                     @_);
-        unless(defined $args{'Principal'}) {
-                $RT::Logger->debug("Principal undefined in Queue::HasRight");
+    my ($walker, $deps) = @_;
+
+    $self->SUPER::FindDependencies($walker, $deps);
+
+    # Queue role groups( Cc, AdminCc )
+    my $objs = RT::Groups->new( $self->CurrentUser );
+    $objs->Limit( FIELD => 'Domain', VALUE => 'RT::Queue-Role', CASESENSITIVE => 0 );
+    $objs->Limit( FIELD => 'Instance', VALUE => $self->Id );
+    $deps->Add( in => $objs );
+
+    # Scrips
+    $objs = RT::ObjectScrips->new( $self->CurrentUser );
+    $objs->Limit( FIELD           => 'ObjectId',
+                  OPERATOR        => '=',
+                  VALUE           => $self->id,
+                  ENTRYAGGREGATOR => 'OR' );
+    $objs->Limit( FIELD           => 'ObjectId',
+                  OPERATOR        => '=',
+                  VALUE           => 0,
+                  ENTRYAGGREGATOR => 'OR' );
+    $deps->Add( in => $objs );
+
+    # Templates (global ones have already been dealt with)
+    $objs = RT::Templates->new( $self->CurrentUser );
+    $objs->Limit( FIELD => 'Queue', VALUE => $self->Id);
+    $deps->Add( in => $objs );
+
+    # Custom Fields on things _in_ this queue (CFs on the queue itself
+    # have already been dealt with)
+    $objs = RT::ObjectCustomFields->new( $self->CurrentUser );
+    $objs->Limit( FIELD           => 'ObjectId',
+                  OPERATOR        => '=',
+                  VALUE           => $self->id,
+                  ENTRYAGGREGATOR => 'OR' );
+    $objs->Limit( FIELD           => 'ObjectId',
+                  OPERATOR        => '=',
+                  VALUE           => 0,
+                  ENTRYAGGREGATOR => 'OR' );
+    my $cfs = $objs->Join(
+        ALIAS1 => 'main',
+        FIELD1 => 'CustomField',
+        TABLE2 => 'CustomFields',
+        FIELD2 => 'id',
+    );
+    $objs->Limit( ALIAS    => $cfs,
+                  FIELD    => 'LookupType',
+                  OPERATOR => 'STARTSWITH',
+                  VALUE    => 'RT::Queue-' );
+    $deps->Add( in => $objs );
+
+    # Tickets
+    $objs = RT::Tickets->new( $self->CurrentUser );
+    $objs->Limit( FIELD => "Queue", VALUE => $self->Id );
+    $objs->{allow_deleted_search} = 1;
+    $deps->Add( in => $objs );
+}
 
-        }
-        return($args{'Principal'}->HasQueueRight(QueueObj => $self,
-          Right => $args{'Right'}));
+sub __DependsOn {
+    my $self = shift;
+    my %args = (
+        Shredder => undef,
+        Dependencies => undef,
+        @_,
+    );
+    my $deps = $args{'Dependencies'};
+    my $list = [];
+
+# Tickets
+    my $objs = RT::Tickets->new( $self->CurrentUser );
+    $objs->{'allow_deleted_search'} = 1;
+    $objs->Limit( FIELD => 'Queue', VALUE => $self->Id );
+    push( @$list, $objs );
+
+# Queue role groups( Cc, AdminCc )
+    $objs = RT::Groups->new( $self->CurrentUser );
+    $objs->Limit( FIELD => 'Domain', VALUE => 'RT::Queue-Role', CASESENSITIVE => 0 );
+    $objs->Limit( FIELD => 'Instance', VALUE => $self->Id );
+    push( @$list, $objs );
+
+# Scrips
+    $objs = RT::Scrips->new( $self->CurrentUser );
+    $objs->LimitToQueue( $self->id );
+    push( @$list, $objs );
+
+# Templates
+    $objs = $self->Templates;
+    push( @$list, $objs );
+
+# Custom Fields
+    $objs = RT::CustomFields->new( $self->CurrentUser );
+    $objs->SetContextObject( $self );
+    $objs->LimitToQueue( $self->id );
+    push( @$list, $objs );
+
+    $deps->_PushDependencies(
+        BaseObject => $self,
+        Flags => RT::Shredder::Constants::DEPENDS_ON,
+        TargetObjects => $list,
+        Shredder => $args{'Shredder'}
+    );
+    return $self->SUPER::__DependsOn( %args );
+}
+
+
+sub PreInflate {
+    my $class = shift;
+    my ($importer, $uid, $data) = @_;
+
+    $class->SUPER::PreInflate( $importer, $uid, $data );
+
+    $data->{Name} = $importer->Qualify($data->{Name})
+        if $data->{Name} ne "___Approvals";
+
+    return if $importer->MergeBy( "Name", $class, $uid, $data );
+
+    return 1;
 }
-# }}}
 
-# }}}
+
+
+RT::Base->_ImportOverlays();
 
 1;