—#!perl
# vim: softtabstop=4 tabstop=4 shiftwidth=4 ft=perl expandtab smarttab
# PODNAME: RT::Client::REST::Ticket
# ABSTRACT: ticket object representation.
use
strict;
use
warnings;
package
RT::Client::REST::Ticket;
$RT::Client::REST::Ticket::VERSION
=
'0.72'
;
use
Try::Tiny;
use
RT::Client::REST;
sub
_attributes {{
id
=> {
validation
=> {
type
=> SCALAR,
regex
=>
qr/^\d+$/
,
},
form2value
=>
sub
{
shift
=~ m~^ticket/(\d+)$~i;
return
$1;
},
value2form
=>
sub
{
return
'ticket/'
.
shift
;
},
},
queue
=> {
validation
=> {
type
=> SCALAR,
},
},
owner
=> {
validation
=> {
type
=> SCALAR,
},
},
creator
=> {
validation
=> {
type
=> SCALAR,
},
},
subject
=> {
validation
=> {
type
=> SCALAR,
},
},
status
=> {
validation
=> {
# That's it for validation... People can create their own
# custom statuses.
type
=> SCALAR,
},
rest_name
=>
'Status'
,
},
priority
=> {
validation
=> {
type
=> SCALAR,
},
},
initial_priority
=> {
validation
=> {
type
=> SCALAR,
},
rest_name
=>
'InitialPriority'
,
},
final_priority
=> {
validation
=> {
type
=> SCALAR,
},
rest_name
=>
'FinalPriority'
,
},
requestors
=> {
validation
=> {
type
=> ARRAYREF,
},
list
=> 1,
},
requestor
=> {
validation
=> {
type
=> ARRAYREF,
},
list
=> 1,
},
cc
=> {
validation
=> {
type
=> ARRAYREF,
},
list
=> 1,
},
admin_cc
=> {
validation
=> {
type
=> ARRAYREF,
},
list
=> 1,
rest_name
=>
'AdminCc'
,
},
created
=> {
validation
=> {
type
=> SCALAR,
},
is_datetime
=> 1,
},
starts
=> {
validation
=> {
type
=> SCALAR|UNDEF,
},
is_datetime
=> 1,
},
started
=> {
validation
=> {
type
=> SCALAR|UNDEF,
},
is_datetime
=> 1,
},
due
=> {
validation
=> {
type
=> SCALAR|UNDEF,
},
is_datetime
=> 1,
},
resolved
=> {
validation
=> {
type
=> SCALAR|UNDEF,
},
is_datetime
=> 1,
},
told
=> {
validation
=> {
type
=> SCALAR|UNDEF,
},
is_datetime
=> 1,
},
time_estimated
=> {
validation
=> {
type
=> SCALAR,
},
rest_name
=>
'TimeEstimated'
,
},
time_worked
=> {
validation
=> {
type
=> SCALAR,
},
rest_name
=>
'TimeWorked'
,
},
time_left
=> {
validation
=> {
type
=> SCALAR,
},
rest_name
=>
'TimeLeft'
,
},
last_updated
=> {
validation
=> {
type
=> SCALAR,
},
rest_name
=>
'LastUpdated'
,
is_datetime
=> 1,
},
sla
=> {
validation
=> {
type
=> SCALAR,
},
},
}}
# comment and correspond are really the same method, so we save ourselves
# some duplication here.
for
my
$method
(
qw(comment correspond)
) {
no
strict
'refs'
;
## no critic (ProhibitNoStrict)
*$method
=
sub
{
my
$self
=
shift
;
if
(
@_
& 1) {
RT::Client::REST::Object::OddNumberOfArgumentsException->throw;
}
$self
->_assert_rt_and_id(
$method
);
my
%opts
=
@_
;
unless
(
defined
(
$opts
{message})) {
RT::Client::REST::Object::InvalidValueException->throw(
"No message was provided"
,
);
}
$self
->rt->
$method
(
ticket_id
=>
$self
->id,
%opts
,
);
return
;
};
}
sub
attachments {
my
$self
=
shift
;
$self
->_assert_rt_and_id;
RT::Client::REST::SearchResult->new(
ids
=> [
$self
->rt->get_attachment_ids(
id
=>
$self
->id) ],
object
=>
sub
{
RT::Client::REST::Attachment->new(
id
=>
shift
,
parent_id
=>
$self
->id,
rt
=>
$self
->rt,
);
},
);
}
sub
transactions {
my
$self
=
shift
;
if
(
@_
& 1) {
RT::Client::REST::Object::OddNumberOfArgumentsException->throw;
}
$self
->_assert_rt_and_id;
my
%opts
=
@_
;
my
%params
= (
parent_id
=>
$self
->id,
);
if
(
defined
(
my
$type
=
delete
(
$opts
{type}))) {
$params
{transaction_type} =
$type
;
}
RT::Client::REST::SearchResult->new(
ids
=> [
$self
->rt->get_transaction_ids(
%params
) ],
object
=>
sub
{
RT::Client::REST::Transaction->new(
id
=>
shift
,
parent_id
=>
$self
->id,
rt
=>
$self
->rt,
);
},
);
}
for
my
$method
(
qw(take untake steal)
) {
no
strict
'refs'
;
## no critic (ProhibitNoStrict)
*$method
=
sub
{
my
$self
=
shift
;
$self
->_assert_rt_and_id(
$method
);
try
{
$self
->rt->
$method
(
id
=>
$self
->id);
}
catch
{
die
$_
unless
blessed
$_
&&
$_
->can(
'rethrow'
);
if
(
$_
->isa(
'RT::Client::REST::AlreadyTicketOwnerException'
)) {
# Rename the exception.
RT::Client::REST::Object::NoopOperationException
->throw(
shift
->message);
}
else
{
$_
->rethrow;
}
};
return
;
};
}
sub
rt_type {
'ticket'
}
__PACKAGE__->_generate_methods;
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
RT::Client::REST::Ticket - ticket object representation.
=head1 VERSION
version 0.72
=head1 SYNOPSIS
my $rt = RT::Client::REST->new(server => $ENV{RTSERVER});
# Create a new ticket:
my $ticket = RT::Client::REST::Ticket->new(
rt => $rt,
queue => "General",
subject => $subject,
)->store(text => "This is the initial text of the ticket");
print "Created a new ticket, ID ", $ticket->id, "\n";
# Update
my $ticket = RT::Client::REST::Ticket->new(
rt => $rt,
id => $id,
priority => 10,
)->store;
# Retrieve
my $ticket => RT::Client::REST::Ticket->new(
rt => $rt,
id => $id,
)->retrieve;
unless ($ticket->owner eq $me) {
$ticket->steal; # Give me more work!
}
=head1 DESCRIPTION
B<RT::Client::REST::Ticket> is based on L<RT::Client::REST::Object>.
The representation allows one to retrieve, edit, comment on, and create
tickets in RT.
=head1 ATTRIBUTES
=over 2
=item B<id>
This is the numeric ID of the ticket.
=item B<queue>
This is the B<name> of the queue (not numeric id).
=item B<owner>
Username of the owner.
=item B<creator>
Username of RT user who created the ticket.
=item B<subject>
Subject of the ticket.
=item B<status>
The status is usually one of the following: "new", "open", "resolved",
"stalled", "rejected", and "deleted". However, custom RT installations
sometimes add their own statuses.
=item B<priority>
Ticket priority. Usually a numeric value.
=item B<initial_priority>
=item B<final_priority>
=for stopwords requestor requestors
=item B<requestor>
This is the attribute for setting the requestor on ticket creation.
If you use requestors to do this in 3.8, the recipient may not receive
an auto-reply from RT because the ticket is initially created as the user
your REST session is connected as.
It is a list attribute (for explanation of list attributes, see
B<LIST ATTRIBUTE PROPERTIES> in L<RT::Client::REST::Object>).
=item B<requestors>
This contains e-mail addresses of the requestors.
It is a list attribute (for explanation of list attributes, see
B<LIST ATTRIBUTE PROPERTIES> in L<RT::Client::REST::Object>).
=item B<cc>
A list of e-mail addresses used to notify people of 'correspond'
actions.
=item B<admin_cc>
A list of e-mail addresses used to notify people of all actions performed
on a ticket.
=item B<created>
Time at which ticket was created. Note that this is an immutable field
and therefore the value cannot be changed..
=item B<starts>
=item B<started>
=item B<due>
=item B<resolved>
=item B<told>
=item B<time_estimated>
=item B<time_worked>
=item B<time_left>
=item B<last_updated>
=back
=head2 Attributes storing a time
The attributes which store a time stamp have an additional accessor with the
suffix C<_datetime> (e.g. C<resolved_datetime>). This allows you can get and
set the stored value as a DateTime object. Internally, it is converted into
the date-time string which RT uses, which is assumed to be in UTC.
=head1 DB METHODS
For full explanation of these, please see B<"DB METHODS"> in
L<RT::Client::REST::Object> documentation.
=over 2
=item B<retrieve>
Retrieve RT ticket from database.
=item B<store ([text =E<gt> $text])>
Create or update the ticket. When creating a new ticket, optional 'text'
parameter can be supplied to set the initial text of the ticket.
=item B<search>
Search for tickets that meet specific conditions.
=back
=head1 TICKET-SPECIFIC METHODS
=over 2
=item B<comment> (message => $message, %opts)
Comment on this ticket with message $message. C<%opts> is a list of
key-value pairs as follows:
=over 2
=item B<attachments>
List of filenames (an array reference) that should be attached to the
ticket along with the comment.
=item B<cc>
List of e-mail addresses to send carbon copies to (an array reference).
=for stopwords bcc
=item B<bcc>
List of e-mail addresses to send blind carbon copies to (an array
reference).
=back
=item B<correspond> (message => $message, %opts)
Add correspondence to the ticket. Takes exactly the same arguments
as the B<comment> method above.
=item B<attachments>
Get attachments associated with this ticket. What is returned is an
object of type L<RT::Client::REST::SearchResult> which can then be used
to get at objects of type L<RT::Client::REST::Attachment>.
=item B<transactions>
Get transactions associated with this ticket. Optionally, you can specify
exactly what types of transactions you want listed, for example:
my $result = $ticket->transactions(type => [qw(Comment Correspond)]);
Please reference L<RT::Client::REST> documentation for the full list of
valid transaction types.
Return value is an object of type L<RT::Client::REST::SearchResult> which
can then be used to iterate over transaction objects
(L<RT::Client::REST::Transaction>).
=item B<take>
Take this ticket.
If you already the owner of this ticket,
C<RT::Client::REST::Object::NoopOperationException> will be thrown.
=for stopwords Untake untake
=item B<untake>
Untake this ticket.
If Nobody is already the owner of this ticket,
C<RT::Client::REST::Object::NoopOperationException> will be thrown.
=item B<steal>
Steal this ticket.
If you already the owner of this ticket,
C<RT::Client::REST::Object::NoopOperationException> will be thrown.
=back
=head1 CUSTOM FIELDS
This class inherits 'cf' method from L<RT::Client::REST::Object>. To create
a ticket with a bunch of custom fields, use the following approach:
RT::Client::REST::Ticket->new(
rt => $rt,
# blah blah
cf => {
'field one' => $value1,
'field two' => $another_value,
},
)->store;
Some more examples:
# Update a custom field value:
$ticket->cf('field one' => $value1);
$ticket->store;
# Get a custom field value:
my $another value = $ticket->cf('field two');
# Get a list of ticket's custom field names:
my @custom_fields = $ticket->cf;
=head1 INTERNAL METHODS
=over 2
=item B<rt_type>
Returns 'ticket'.
=back
=head1 SEE ALSO
L<RT::Client::REST>, L<RT::Client::REST::Object>,
L<RT::Client::REST::Attachment>,
L<RT::Client::REST::SearchResult>,
L<RT::Client::REST::Transaction>.
=head1 AUTHOR
Dean Hamstead <dean@fragfest.com.au>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2023, 2020 by Dmitri Tikhonov.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut