NAME
RT::Extension::TicketAging - allows tickets to be made inaccessable and finally completely deleted
DESCRIPTION
This extension allows closed tickets to be made inaccessable and finally completely deleted as they get older. It adds a new global ticket field, "Age", to track a ticket's movement through the life cycle.
The rt-aging program (see below) is used to move tickets through the life cycle and must be run separately.
When we speak of "age" we are referring to a ticket's "LastUpdated" property.
Default life cycle
The default life cycle is:
- Active
-
Any unresolved ticket or a ticket with unresolved children is considered Active.
- Finished
-
When a ticket and all its children have been resolved it becomes Finished. No further activity is expected on this ticket.
There is otherwise nothing special about a Finished ticket.
- Dead
-
When a ticket and all its children are Finished and it has not been updated for 2 months it becomes Dead. Dead tickets are just like Finished tickets except they do not show up in RTIR's special lookup tools.
- Extinct
-
When a ticket is Dead and has not been updated for 12 months it becomes Extinct. Extinct tickets have their status set to deleted. They won't show up in any searches unless explicitly asked for (
'CF.{Age} = "Extinct"'
). - Destroyed
-
When a ticket is Extinct and has not been updated for 24 months and if all linked tickets are also Extinct a ticket is Destroyed. Destroyed tickets are no longer available in RT. They are wholely removed from RT using the Shredder. Destroyed tickets are saved in a SQL dump file from which they can be restored.
See RT::Shredder for more information.
- Reactivation
-
When users reopen a ticket (change Status from inactive to active) it becomes Active again.
rt-aging
The real work is done by the rt-aging program installed to your RT local sbin. In general you simply run rt-aging from the command line or periodically from cron as an RT administrator. It will apply the aging rules and alter the tickets as necessary.
See rt-aging for more details.
Aging configuration
Library preloading
Add the line use RT::Extension::TicketAging;
to the bottom of the RT site config, etc/RT_SiteConfig.pm
after adding all extension options described below.
This step is required to allow users to search by Extinct age.
ACLs
By default we grant SeeCustomField right to all privileged users.
$TicketAgingFilenameTemplate
This is the filename template used to create the Shredder dump file when tickets are Destroyed. Defaults to the RT::Shredder default. Good candidates:
Set($TicketAgingFilenameTemplate, 'aging-%t.XXXX.sql');
# or
Set($TicketAgingFilenameTemplate, '/var/backups/aging/%t.XXXX.sql');
See the documentation for <RT::Shredder-
GetFileName>> for more details.
$TicketAgingMap
THIS IS AN EXPERIMENTAL FEATURE
Administrators may define their own aging behaviors.
The ages available to RT are configured by changing the available values for the Age
global custom field. An administrator may remove values to disable pre-configured options. Adding new values activates new age commands but if its not one of the above values you have to configure the conditions and actions for each age.
$TicketAgingMap
can be set in your configuration to override or add to the default life cycle. Its easiest to illustrate this with code.
Set( $TicketAgingMap, {
AgeName => {
Condition => {
CallbackPre => sub { ... },
SQL => sub { ... },
CallbackPost => sub { ... },
Filter => sub { ... },
},
Action => sub { ... }
}
});
Arguments
The aging conditions and actions generally have these arguments:
- Age
-
This is the name of the age being processed. For example "Active".
- Collection
-
This is an RT::Tickets object representing all the tickets visible to the
$RT::SystemUser
. It can be filtered by the Callbacks and the SQL. - Object
-
An individual RT::Ticket from the ticket
Collection
.
Fields
- AgeName
-
The name of your Age field. For example, "Active".
- Condition
-
Holds the rules for determining what tickets fall into this age. The rules are run in this order (excuse the pseudo-code):
CallbackPre SQL CallbackPost foreach $Object ($Collection) { Filter Action }
- SQL
-
This is the TicketSQL to be run to get the tickets of this Age. Generally its a check against LastUpdated and perhaps Status.
SQL => sub { "LastUpdated < '-2 months'" }
The TicketSQL is run against the Collection.
Called with
Age
andCollection
arguments.Should return a valid TicketSQL string.
- CallbackPre
- CallbackPost
-
These callbacks can be used to alter the Collection before the SQL is run or before the Filter.
Called with
Age
andCollection
arguments.Must return true on success or a tuple of
(false, $error_message)
on failure.For example:
# Search for deleted tickets CallbackPre => sub { my %args = @_; return $args{Collection}{allow_deleted_search} = 1; };
- Filter
-
Each ticket found by the SQL condition in the
Collection
is iterated over and theFilter
is called on each one. This gives an opportunity to cull out individual tickets.Called with
Age
,Collection
andObject
arguments.Object
is an individual RT::Ticket from the ticketCollection
.Returns true if the ticket should be included in the age, false if it should be ignored.
# Filter out tickets whose children are not of the same age. Filter => sub { my %args = @_; my $id = $args{Object}->id; my $find_different_children = qq{ (CF.{Age} IS NULL OR CF.{Age} != $args{Age}) AND Linked = $id }; my $tickets = RT::Tickets->new( $RT::SystemUser ); $tickets->{allow_deleted_search} = 1; $tickets->FromSQL( $find_different_children ); return !$tickets->Count; }
- Action
-
After filtering, each ticket found in the
Collection
is iterated over and theAction
is called on each one. This is where whatever changes that need to be made to individual tickets when they change age should be done.Called with
Age
,Collection
andObject
arguments.Like the Callbacks, it returns true on success or a tuple of
(false, $error_message)
on failure.# Mark the ticket as deleted. Action => sub { my %args = @_; my $ticket = $args{Object}; return $ticket->__Set( Field => "Status", Value => "deleted" ); }
AUTHOR
Ruslan Zakirov <ruz@bestpractical.com>