-Returns: TICKETID, Transaction Object, Error Message
-
-
-=begin testing
-
-my $t = RT::Ticket->new($RT::SystemUser);
-
-ok( $t->Create(Queue => 'General', Subject => 'This is a subject'), "Ticket Created");
-
-ok ( my $id = $t->Id, "Got ticket id");
-
-=end testing
-
-=cut
-
-sub Create {
- my $self = shift;
-
- my %args = (
- Queue => undef,
- Requestor => undef,
- Cc => undef,
- AdminCc => undef,
- Type => 'ticket',
- Owner => $RT::Nobody->UserObj,
- Subject => '[no subject]',
- InitialPriority => undef,
- FinalPriority => undef,
- Status => 'new',
- TimeWorked => "0",
- TimeLeft => 0,
- Due => undef,
- Starts => undef,
- MIMEObj => undef,
- @_);
-
- my ($ErrStr, $QueueObj, $Owner, $resolved);
- my (@non_fatal_errors);
-
- my $now = RT::Date->new($self->CurrentUser);
- $now->SetToNow();
-
- if ( (defined($args{'Queue'})) && (!ref($args{'Queue'})) ) {
- $QueueObj=RT::Queue->new($RT::SystemUser);
- $QueueObj->Load($args{'Queue'});
- }
- elsif (ref($args{'Queue'}) eq 'RT::Queue') {
- $QueueObj=RT::Queue->new($RT::SystemUser);
- $QueueObj->Load($args{'Queue'}->Id);
- }
- else {
- $RT::Logger->debug("$self ". $args{'Queue'} .
- " not a recognised queue object.");
- }
-
- #Can't create a ticket without a queue.
- unless (defined ($QueueObj)) {
- $RT::Logger->debug( "$self No queue given for ticket creation.");
- return (0, 0,'Could not create ticket. Queue not set');
- }
-
- #Now that we have a queue, Check the ACLS
- unless ($self->CurrentUser->HasQueueRight(Right => 'CreateTicket',
- QueueObj => $QueueObj )) {
- return (0,0,"No permission to create tickets in the queue '".
- $QueueObj->Name."'.");
- }
-
- #Since we have a queue, we can set queue defaults
- #Initial Priority
-
- # If there's no queue default initial priority and it's not set, set it to 0
- $args{'InitialPriority'} = ($QueueObj->InitialPriority || 0)
- unless (defined $args{'InitialPriority'});
-
- #Final priority
-
- # If there's no queue default final priority and it's not set, set it to 0
- $args{'FinalPriority'} = ($QueueObj->FinalPriority || 0)
- unless (defined $args{'FinalPriority'});
-
-
- #TODO we should see what sort of due date we're getting, rather +
- # than assuming it's in ISO format.
-
- #Set the due date. if we didn't get fed one, use the queue default due in
- my $due = new RT::Date($self->CurrentUser);
- if (defined $args{'Due'}) {
- $due->Set (Format => 'ISO',
- Value => $args{'Due'});
- }
- elsif (defined ($QueueObj->DefaultDueIn)) {
- $due->SetToNow;
- $due->AddDays($QueueObj->DefaultDueIn);
- }
-
- my $starts = new RT::Date($self->CurrentUser);
- if (defined $args{'Starts'}) {
- $starts->Set (Format => 'ISO',
- Value => $args{'Starts'});
- }
-
-
- # {{{ Deal with setting the owner
-
- if (ref($args{'Owner'}) eq 'RT::User') {
- $Owner = $args{'Owner'};
- }
- #If we've been handed something else, try to load the user.
- elsif ($args{'Owner'}) {
- $Owner = new RT::User($self->CurrentUser);
- $Owner->Load($args{'Owner'});
-
- }
- #If we can't handle it, call it nobody
- else {
- if (ref($args{'Owner'})) {
- $RT::Logger->warning("$ticket ->Create called with an Owner of ".
- "type ".ref($args{'Owner'}) .". Defaulting to nobody.\n");
-
- push @non_fatal_errors, "Invalid owner. Defaulting to 'nobody'.";
- }
- else {
- $RT::Logger->warning("$self ->Create called with an ".
- "unknown datatype for Owner: ".$args{'Owner'} .
- ". Defaulting to Nobody.\n");
- }
- }
-
- #If we have a proposed owner and they don't have the right
- #to own a ticket, scream about it and make them not the owner
- if ((defined ($Owner)) and
- ($Owner->Id != $RT::Nobody->Id) and
- (!$Owner->HasQueueRight( QueueObj => $QueueObj,
- Right => 'OwnTicket'))) {
-
- $RT::Logger->warning("$self user ".$Owner->Name . "(".$Owner->id .
- ") was proposed ".
- "as a ticket owner but has no rights to own ".
- "tickets in this queue\n");
-
- push @non_fatal_errors, "Invalid owner. Defaulting to 'nobody'.";
-
- $Owner = undef;
- }
-
- #If we haven't been handed a valid owner, make it nobody.
- unless (defined ($Owner)) {
- $Owner = new RT::User($self->CurrentUser);
- $Owner->Load($RT::Nobody->UserObj->Id);
- }
-
- # }}}
-
- unless ($self->ValidateStatus($args{'Status'})) {
- return (0,0,'Invalid value for status');
- }
-
- if ($args{'Status'} eq 'resolved') {
- $resolved = $now->ISO;
- } else{
- $resolved = undef;
- }
-
- my $id = $self->SUPER::Create(
- Queue => $QueueObj->Id,
- Owner => $Owner->Id,
- Subject => $args{'Subject'},
- InitialPriority => $args{'InitialPriority'},
- FinalPriority => $args{'FinalPriority'},
- Priority => $args{'InitialPriority'},
- Status => $args{'Status'},
- TimeWorked => $args{'TimeWorked'},
- TimeLeft => $args{'TimeLeft'},
- Type => $args{'Type'},
- Starts => $starts->ISO,
- Resolved => $resolved,
- Due => $due->ISO
- );
- #Set the ticket's effective ID now that we've created it.
- my ($val, $msg) = $self->__Set(Field => 'EffectiveId', Value => $id);
-
- unless ($val) {
- $RT::Logger->err("$self ->Create couldn't set EffectiveId: $msg\n");
- }
-
-
- my $watcher;
- foreach $watcher (@{$args{'Cc'}}) {
- my ($wval, $wmsg) =
- $self->_AddWatcher( Type => 'Cc', Person => $watcher, Silent => 1);
- push @non_fatal_errors, $wmsg unless ($wval);
- }
-
- foreach $watcher (@{$args{'Requestor'}}) {
- my ($wval, $wmsg) =
- $self->_AddWatcher( Type => 'Requestor', Person => $watcher, Silent => 1);
- push @non_fatal_errors, $wmsg unless ($wval);
- }
-
- foreach $watcher (@{$args{'AdminCc'}}) {
- # Note that we're using AddWatcher, rather than _AddWatcher, as we
- # actually _want_ that ACL check. Otherwise, random ticket creators
- # could make themselves adminccs and maybe get ticket rights. that would
- # be poor
- my ($wval, $wmsg) =
- $self->AddWatcher( Type => 'AdminCc', Person => $watcher, Silent => 1);
- push @non_fatal_errors, $wmsg unless ($wval);
- }
-
- # Iterate through all the KeywordSelect-<int> params passed in, calling _AddKeyword
- # for each of them
-
-
- foreach my $key (keys %args) {
-
- next unless ($key =~ /^KeywordSelect-(.*)$/);
-
- my $ks = $1;
-
-
- my @keywords = ref($args{$key}) eq 'ARRAY' ?
- @{$args{$key}} : ($args{$key});
-
- foreach my $keyword (@keywords) {
- my ($kval, $kmsg) = $self->_AddKeyword(KeywordSelect => $ks,
- Keyword => $keyword,
- Silent => 1);
- }
- push @non_fatal_errors, $kmsg unless ($kval);
- }
-
-
-
- #Add a transaction for the create
- my ($Trans, $Msg, $TransObj) =
- $self->_NewTransaction( Type => "Create",
- TimeTaken => 0,
- MIMEObj=>$args{'MIMEObj'});
-
- # Logging
- if ($self->Id && $Trans) {
- $ErrStr = "Ticket ".$self->Id . " created in queue '". $QueueObj->Name.
- "'.\n" . join("\n", @non_fatal_errors);
-
- $RT::Logger->info($ErrStr);
- }
- else {
- # TODO where does this get errstr from?
- $RT::Logger->warning("Ticket couldn't be created: $ErrStr");
- }
-
- return($self->Id, $TransObj->Id, $ErrStr);
-}
-
-# }}}
-
-# {{{ sub Import
-
-=head2 Import PARAMHASH
-
-Import a ticket.
-Doesn\'t create a transaction.
-Doesn\'t supply queue defaults, etc.
-
-Arguments are identical to Create(), with the addition of
- Id - Ticket Id
-
-Returns: TICKETID
-
-=cut
-
-
-sub Import {
- my $self = shift;
- my ( $ErrStr, $QueueObj, $Owner);
-
- my %args = (id => undef,
- EffectiveId => undef,
- Queue => undef,
- Requestor => undef,
- Type => 'ticket',
- Owner => $RT::Nobody->Id,
- Subject => '[no subject]',
- InitialPriority => undef,
- FinalPriority => undef,
- Status => 'new',
- TimeWorked => "0",
- Due => undef,
- Created => undef,
- Updated => undef,
- Resolved => undef,
- Told => undef,
- @_);
-
- if ( (defined($args{'Queue'})) && (!ref($args{'Queue'})) ) {
- $QueueObj=RT::Queue->new($RT::SystemUser);
- $QueueObj->Load($args{'Queue'});
- #TODO error check this and return 0 if it\'s not loading properly +++
- }
- elsif (ref($args{'Queue'}) eq 'RT::Queue') {
- $QueueObj=RT::Queue->new($RT::SystemUser);
- $QueueObj->Load($args{'Queue'}->Id);
- }
- else {
- $RT::Logger->debug("$self ". $args{'Queue'} .
- " not a recognised queue object.");
- }
-
- #Can't create a ticket without a queue.
- unless (defined ($QueueObj) and $QueueObj->Id) {
- $RT::Logger->debug( "$self No queue given for ticket creation.");
- return (0,'Could not create ticket. Queue not set');
- }
-
- #Now that we have a queue, Check the ACLS
- unless ($self->CurrentUser->HasQueueRight(Right => 'CreateTicket',
- QueueObj => $QueueObj )) {
- return (0,"No permission to create tickets in the queue '".
- $QueueObj->Name."'.");
- }
-
-
-
-
- # {{{ Deal with setting the owner
-
- # Attempt to take user object, user name or user id.
- # Assign to nobody if lookup fails.
- if (defined ($args{'Owner'})) {
- if ( ref($args{'Owner'}) ) {
- $Owner = $args{'Owner'};
- }
- else {
- $Owner = new RT::User($self->CurrentUser);
- $Owner->Load($args{'Owner'});
- if ( ! defined($Owner->id) ) {
- $Owner->Load($RT::Nobody->id);
- }
- }
- }
-
-
- #If we have a proposed owner and they don't have the right
- #to own a ticket, scream about it and make them not the owner
- if ((defined ($Owner)) and
- ($Owner->Id != $RT::Nobody->Id) and
- (!$Owner->HasQueueRight( QueueObj => $QueueObj,
- Right => 'OwnTicket'))) {
-
- $RT::Logger->warning("$self user ".$Owner->Name . "(".$Owner->id .
- ") was proposed ".
- "as a ticket owner but has no rights to own ".
- "tickets in '".$QueueObj->Name."'\n");
-
- $Owner = undef;
- }
-
- #If we haven't been handed a valid owner, make it nobody.
- unless (defined ($Owner)) {
- $Owner = new RT::User($self->CurrentUser);
- $Owner->Load($RT::Nobody->UserObj->Id);
- }
-
- # }}}
-
- unless ($self->ValidateStatus($args{'Status'})) {
- return (0,"'$args{'Status'}' is an invalid value for status");
- }
-
- $self->{'_AccessibleCache'}{Created} = { 'read'=>1, 'write'=>1 };
- $self->{'_AccessibleCache'}{Creator} = { 'read'=>1, 'auto'=>1 };
- $self->{'_AccessibleCache'}{LastUpdated} = { 'read'=>1, 'write'=>1 };
- $self->{'_AccessibleCache'}{LastUpdatedBy} = { 'read'=>1, 'auto'=>1 };
-
-
- # If we're coming in with an id, set that now.
- my $EffectiveId = undef;
- if ($args{'id'}) {
- $EffectiveId = $args{'id'};
-
- }
-
-
- my $id = $self->SUPER::Create(
- id => $args{'id'},
- EffectiveId => $EffectiveId,
- Queue => $QueueObj->Id,
- Owner => $Owner->Id,
- Subject => $args{'Subject'},
- InitialPriority => $args{'InitialPriority'},
- FinalPriority => $args{'FinalPriority'},
- Priority => $args{'InitialPriority'},
- Status => $args{'Status'},
- TimeWorked => $args{'TimeWorked'},
- Type => $args{'Type'},
- Created => $args{'Created'},
- Told => $args{'Told'},
- LastUpdated => $args{'Updated'},
- Resolved => $args{Resolved},
- Due => $args{'Due'},
- );
-
-
-
- # If the ticket didn't have an id
- # Set the ticket's effective ID now that we've created it.
- if ($args{'id'} ) {
- $self->Load($args{'id'});
- }
- else {
- my ($val, $msg) = $self->__Set(Field => 'EffectiveId', Value => $id);
-
- unless ($val) {
- $RT::Logger->err($self."->Import couldn't set EffectiveId: $msg\n");
- }
- }
-
- my $watcher;
- foreach $watcher (@{$args{'Cc'}}) {
- $self->_AddWatcher( Type => 'Cc', Person => $watcher, Silent => 1);
- }
- foreach $watcher (@{$args{'AdminCc'}}) {
- $self->_AddWatcher( Type => 'AdminCc', Person => $watcher, Silent => 1);
- }
- foreach $watcher (@{$args{'Requestor'}}) {
- $self->_AddWatcher( Type => 'Requestor', Person => $watcher, Silent => 1);
- }
-
- return($self->Id, $ErrStr);
-}
-
-# }}}
-
-# {{{ sub Delete
-
-sub Delete {
- my $self = shift;
- return (0, 'Deleting this object would violate referential integrity.'.
- ' That\'s bad.');
-}
-# }}}
-
-# {{{ Routines dealing with watchers.
-
-# {{{ Routines dealing with adding new watchers
-
-# {{{ sub AddWatcher
-
-=head2 AddWatcher
-
-AddWatcher takes a parameter hash. The keys are as follows:
-
-Email
-Type
-Owner
-
-If the watcher you\'re trying to set has an RT account, set the Owner paremeter to their User Id. Otherwise, set the Email parameter to their Email address.
-
-=cut
-
-sub AddWatcher {
- my $self = shift;
- my %args = ( Email => undef,
- Type => undef,
- Owner => undef,
- @_
- );
-
- # {{{ Check ACLS
- #If the watcher we're trying to add is for the current user
- if ( ( $self->CurrentUser->EmailAddress &&
- ($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 'ModifyTicket', bail
- if ($args{'Type'} eq 'AdminCc') {
- unless ($self->CurrentUserHasRight('ModifyTicket') or
- $self->CurrentUserHasRight('WatchAsAdminCc')) {
- return(0, 'Permission Denied');
- }
- }
-
- # If it's a Requestor or Cc and they don't have
- # 'Watch' or 'ModifyTicket', bail
- elsif (($args{'Type'} eq 'Cc') or
- ($args{'Type'} eq 'Requestor')) {
-
- unless ($self->CurrentUserHasRight('ModifyTicket') 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 TicketAddWatcher');
- }
- }
- # If the watcher isn't the current user
- # and the current user doesn't have 'ModifyTicket'
- # bail
- else {
- unless ($self->CurrentUserHasRight('ModifyTicket')) {
- return (0, "Permission Denied");
- }
- }
- # }}}
-
- return ($self->_AddWatcher(%args));