package HTML::Mason::Commands;
use strict;
+no warnings qw(redefine);
=head2 ProcessTicketCustomers
}
###
+ ###
+ #find new services
+ ###
+
+ my @svcnums = map { /^Ticket-AddService-(\d+)$/; $1 }
+ grep { /^Ticket-AddService-(\d+)$/ && $ARGSRef->{$_} }
+ keys %$ARGSRef;
+
+ my @custnums;
+ foreach my $svcnum (@svcnums) {
+ my @link = ( 'Type' => 'MemberOf',
+ 'Target' => "freeside://freeside/cust_svc/$svcnum",
+ );
+
+ my( $val, $msg ) = $Ticket->AddLink(@link);
+ push @results, $msg;
+ next if !$val;
+
+ }
+
###
#find new customers
###
- my @custnums = map { /^Ticket-AddCustomer-(\d+)$/; $1 }
- grep { /^Ticket-AddCustomer-(\d+)$/ && $ARGSRef->{$_} }
- keys %$ARGSRef;
+ push @custnums, map { /^Ticket-AddCustomer-(\d+)$/; $1 }
+ grep { /^Ticket-AddCustomer-(\d+)$/ && $ARGSRef->{$_} }
+ keys %$ARGSRef;
#my @delete_custnums =
# map { /^Ticket-AddCustomer-(\d+)$/; $1 }
}
+ ###
+ #remove any declared non-customer addresses
+ ###
+
+ my $exclude_regexp = RT->Config->Get('NonCustomerEmailRegexp');
+ @Requestors = grep { not $_->EmailAddress =~ $exclude_regexp } @Requestors
+ if defined $exclude_regexp;
+
###
#link ticket (and requestors) to customers
###
}
+=head2 ProcessTicketBasics ( TicketObj => $Ticket, ARGSRef => \%ARGS );
+
+Updates all core ticket fields except Status, and returns an array of results
+messages.
+
+=cut
+
+sub ProcessTicketBasics {
+
+ my %args = (
+ TicketObj => undef,
+ ARGSRef => undef,
+ @_
+ );
+
+ my $TicketObj = $args{'TicketObj'};
+ my $ARGSRef = $args{'ARGSRef'};
+
+ # {{{ Set basic fields
+ my @attribs = qw(
+ Subject
+ FinalPriority
+ Priority
+ TimeEstimated
+ TimeWorked
+ TimeLeft
+ Type
+ Queue
+ WillResolve
+ );
+
+ # the UI for editing WillResolve through Ticket Basics should allow
+ # setting it to null
+ if ( exists $ARGSRef->{'WillResolve_Date'} ) {
+ my $to_date = delete($ARGSRef->{'WillResolve_Date'});
+ my $DateObj = RT::Date->new($session{'CurrentUser'});
+ if ( $to_date ) {
+ $DateObj->Set(Format => 'unknown', Value => $to_date);
+ $ARGSRef->{'WillResolve'} = $DateObj->ISO;
+ } elsif ( $TicketObj and $TicketObj->WillResolveObj->Unix > 0 ) {
+ $DateObj->Set(Value => 0);
+ $ARGSRef->{'WillResolve'} = $DateObj->ISO;
+ }
+ }
+
+ if ( $ARGSRef->{'Queue'} and ( $ARGSRef->{'Queue'} !~ /^(\d+)$/ ) ) {
+ my $tempqueue = RT::Queue->new($RT::SystemUser);
+ $tempqueue->Load( $ARGSRef->{'Queue'} );
+ if ( $tempqueue->id ) {
+ $ARGSRef->{'Queue'} = $tempqueue->id;
+ }
+ }
+
+ my @results = UpdateRecordObject(
+ AttributesRef => \@attribs,
+ Object => $TicketObj,
+ ARGSRef => $ARGSRef,
+ );
+
+ # We special case owner changing, so we can use ForceOwnerChange
+ if ( $ARGSRef->{'Owner'} && ( $TicketObj->Owner != $ARGSRef->{'Owner'} ) ) {
+ my ($ChownType);
+ if ( $ARGSRef->{'ForceOwnerChange'} ) {
+ $ChownType = "Force";
+ } else {
+ $ChownType = "Give";
+ }
+
+ my ( $val, $msg ) = $TicketObj->SetOwner( $ARGSRef->{'Owner'}, $ChownType );
+ push( @results, $msg );
+ }
+
+ return (@results);
+}
+
+=head2 ProcessTicketDates (TicketObj => RT::Ticket, ARGSRef => {})
+
+Process updates to the Starts, Started, Told, Resolved, and WillResolve
+fields.
+
+=cut
+
+sub ProcessTicketDates {
+ my %args = (
+ TicketObj => undef,
+ ARGSRef => undef,
+ @_
+ );
+
+ my $Ticket = $args{'TicketObj'};
+ my $ARGSRef = $args{'ARGSRef'};
+
+ my (@results);
+
+ # {{{ Set date fields
+ my @date_fields = qw(
+ Told
+ Resolved
+ Starts
+ Started
+ Due
+ WillResolve
+ );
+
+ #Run through each field in this list. update the value if apropriate
+ foreach my $field (@date_fields) {
+ next unless exists $ARGSRef->{ $field . '_Date' };
+ next if $ARGSRef->{ $field . '_Date' } eq '';
+
+ my ( $code, $msg );
+
+ my $DateObj = RT::Date->new( $session{'CurrentUser'} );
+ $DateObj->Set(
+ Format => 'unknown',
+ Value => $ARGSRef->{ $field . '_Date' }
+ );
+
+ my $obj = $field . "Obj";
+ if ( ( defined $DateObj->Unix )
+ and ( $DateObj->Unix != $Ticket->$obj()->Unix() ) )
+ {
+ my $method = "Set$field";
+ my ( $code, $msg ) = $Ticket->$method( $DateObj->ISO );
+ push @results, "$msg";
+ }
+ }
+
+ # }}}
+ return (@results);
+}
+
+=head2 ProcessTicketStatus (TicketObj => RT::Ticket, ARGSRef => {})
+
+Process updates to the 'Status' field of the ticket. If the new value
+of Status is 'resolved', this will check required custom fields before
+allowing the update.
+
+=cut
+
+sub ProcessTicketStatus {
+ my %args = (
+ TicketObj => undef,
+ ARGSRef => undef,
+ @_
+ );
+
+ my $TicketObj = $args{'TicketObj'};
+ my $ARGSRef = $args{'ARGSRef'};
+ my @results;
+
+ return () if !$ARGSRef->{'Status'};
+
+ if ( lc( $ARGSRef->{'Status'} ) eq 'resolved' ) {
+ foreach my $field ( $TicketObj->MissingRequiredFields ) {
+ push @results, loc('Missing required field: [_1]', $field->Name);
+ }
+ }
+ if ( @results ) {
+ $m->notes('RedirectToBasics' => 1);
+ return @results;
+ }
+
+ return UpdateRecordObject(
+ AttributesRef => [ 'Status' ],
+ Object => $TicketObj,
+ ARGSRef => $ARGSRef,
+ );
+}
+
+=head2 ProcessUpdateMessage
+
+Takes paramhash with fields ARGSRef, TicketObj and SkipSignatureOnly.
+
+Don't write message if it only contains current user's signature and
+SkipSignatureOnly argument is true. Function anyway adds attachments
+and updates time worked field even if skips message. The default value
+is true.
+
+=cut
+
+# change from stock: if txn custom fields are set but there's no content
+# or attachment, create a Touch txn instead of doing nothing
+
+sub ProcessUpdateMessage {
+
+ my %args = (
+ ARGSRef => undef,
+ TicketObj => undef,
+ SkipSignatureOnly => 1,
+ @_
+ );
+
+ if ( $args{ARGSRef}->{'UpdateAttachments'}
+ && !keys %{ $args{ARGSRef}->{'UpdateAttachments'} } )
+ {
+ delete $args{ARGSRef}->{'UpdateAttachments'};
+ }
+
+ # Strip the signature
+ $args{ARGSRef}->{UpdateContent} = RT::Interface::Web::StripContent(
+ Content => $args{ARGSRef}->{UpdateContent},
+ ContentType => $args{ARGSRef}->{UpdateContentType},
+ StripSignature => $args{SkipSignatureOnly},
+ CurrentUser => $args{'TicketObj'}->CurrentUser,
+ );
+
+ my %txn_customfields;
+
+ foreach my $key ( keys %{ $args{ARGSRef} } ) {
+ if ( $key =~ /^(?:Object-RT::Transaction--)?CustomField-(\d+)/ ) {
+ next if $key =~ /(TimeUnits|Magic)$/;
+ $txn_customfields{$key} = $args{ARGSRef}->{$key};
+ }
+ }
+
+ # If, after stripping the signature, we have no message, create a
+ # Touch transaction if necessary
+ if ( not $args{ARGSRef}->{'UpdateAttachments'}
+ and not length $args{ARGSRef}->{'UpdateContent'} )
+ {
+ #if ( $args{ARGSRef}->{'UpdateTimeWorked'} ) {
+ # $args{ARGSRef}->{TimeWorked} = $args{TicketObj}->TimeWorked +
+ # delete $args{ARGSRef}->{'UpdateTimeWorked'};
+ # }
+
+ my $timetaken = $args{ARGSRef}->{'UpdateTimeWorked'};
+ if ( $timetaken or grep {length $_} values %txn_customfields ) {
+ my ( $Transaction, $Description, $Object ) =
+ $args{TicketObj}->Touch(
+ CustomFields => \%txn_customfields,
+ TimeTaken => $timetaken
+ );
+ return $Description;
+ }
+
+ return;
+ }
+
+ if ( $args{ARGSRef}->{'UpdateSubject'} eq $args{'TicketObj'}->Subject ) {
+ $args{ARGSRef}->{'UpdateSubject'} = undef;
+ }
+
+ my $Message = MakeMIMEEntity(
+ Subject => $args{ARGSRef}->{'UpdateSubject'},
+ Body => $args{ARGSRef}->{'UpdateContent'},
+ Type => $args{ARGSRef}->{'UpdateContentType'},
+ );
+
+ $Message->head->add( 'Message-ID' => Encode::encode_utf8(
+ RT::Interface::Email::GenMessageId( Ticket => $args{'TicketObj'} )
+ ) );
+ my $old_txn = RT::Transaction->new( $session{'CurrentUser'} );
+ if ( $args{ARGSRef}->{'QuoteTransaction'} ) {
+ $old_txn->Load( $args{ARGSRef}->{'QuoteTransaction'} );
+ } else {
+ $old_txn = $args{TicketObj}->Transactions->First();
+ }
+
+ if ( my $msg = $old_txn->Message->First ) {
+ RT::Interface::Email::SetInReplyTo(
+ Message => $Message,
+ InReplyTo => $msg
+ );
+ }
+
+ if ( $args{ARGSRef}->{'UpdateAttachments'} ) {
+ $Message->make_multipart;
+ $Message->add_part($_) foreach values %{ $args{ARGSRef}->{'UpdateAttachments'} };
+ }
+
+ if ( $args{ARGSRef}->{'AttachTickets'} ) {
+ require RT::Action::SendEmail;
+ RT::Action::SendEmail->AttachTickets( RT::Action::SendEmail->AttachTickets,
+ ref $args{ARGSRef}->{'AttachTickets'}
+ ? @{ $args{ARGSRef}->{'AttachTickets'} }
+ : ( $args{ARGSRef}->{'AttachTickets'} ) );
+ }
+
+ my $bcc = $args{ARGSRef}->{'UpdateBcc'};
+ my $cc = $args{ARGSRef}->{'UpdateCc'};
+
+ my %message_args = (
+ CcMessageTo => $cc,
+ BccMessageTo => $bcc,
+ Sign => $args{ARGSRef}->{'Sign'},
+ Encrypt => $args{ARGSRef}->{'Encrypt'},
+ MIMEObj => $Message,
+ TimeTaken => $args{ARGSRef}->{'UpdateTimeWorked'},
+ CustomFields => \%txn_customfields,
+ );
+
+ my @temp_squelch;
+ foreach my $type (qw(Cc AdminCc)) {
+ if (grep $_ eq $type || $_ eq ( $type . 's' ), @{ $args{ARGSRef}->{'SkipNotification'} || [] }) {
+ push @temp_squelch, map $_->address, Email::Address->parse( $message_args{$type} );
+ push @temp_squelch, $args{TicketObj}->$type->MemberEmailAddresses;
+ push @temp_squelch, $args{TicketObj}->QueueObj->$type->MemberEmailAddresses;
+ }
+ }
+ if (grep $_ eq 'Requestor' || $_ eq 'Requestors', @{ $args{ARGSRef}->{'SkipNotification'} || [] }) {
+ push @temp_squelch, map $_->address, Email::Address->parse( $message_args{Requestor} );
+ push @temp_squelch, $args{TicketObj}->Requestors->MemberEmailAddresses;
+ }
+
+ if (@temp_squelch) {
+ require RT::Action::SendEmail;
+ RT::Action::SendEmail->SquelchMailTo( RT::Action::SendEmail->SquelchMailTo, @temp_squelch );
+ }
+
+ unless ( $args{'ARGSRef'}->{'UpdateIgnoreAddressCheckboxes'} ) {
+ foreach my $key ( keys %{ $args{ARGSRef} } ) {
+ next unless $key =~ /^Update(Cc|Bcc)-(.*)$/;
+
+ my $var = ucfirst($1) . 'MessageTo';
+ my $value = $2;
+ if ( $message_args{$var} ) {
+ $message_args{$var} .= ", $value";
+ } else {
+ $message_args{$var} = $value;
+ }
+ }
+ }
+
+ my @results;
+ # Do the update via the appropriate Ticket method
+ if ( $args{ARGSRef}->{'UpdateType'} =~ /^(private|public)$/ ) {
+ my ( $Transaction, $Description, $Object ) =
+ $args{TicketObj}->Comment(%message_args);
+ push( @results, $Description );
+ #$Object->UpdateCustomFields( ARGSRef => $args{ARGSRef} ) if $Object;
+ } elsif ( $args{ARGSRef}->{'UpdateType'} eq 'response' ) {
+ my ( $Transaction, $Description, $Object ) =
+ $args{TicketObj}->Correspond(%message_args);
+ push( @results, $Description );
+ #$Object->UpdateCustomFields( ARGSRef => $args{ARGSRef} ) if $Object;
+ } else {
+ push( @results,
+ loc("Update type was neither correspondence nor comment.") . " " . loc("Update not recorded.") );
+ }
+ return @results;
+}
+
+sub default_FormatDate { $_[0]->AsString }
+
+sub ProcessColumnMapValue {
+ my $value = shift;
+ my %args = ( Arguments => [],
+ Escape => 1,
+ FormatDate => \&default_FormatDate,
+ @_ );
+
+ if ( ref $value ) {
+ if ( ref $value eq 'RT::Date' ) {
+ return $args{FormatDate}->($value);
+ } elsif ( UNIVERSAL::isa( $value, 'CODE' ) ) {
+ my @tmp = $value->( @{ $args{'Arguments'} } );
+ return ProcessColumnMapValue( ( @tmp > 1 ? \@tmp : $tmp[0] ), %args );
+ } elsif ( UNIVERSAL::isa( $value, 'ARRAY' ) ) {
+ return join '', map ProcessColumnMapValue( $_, %args ), @$value;
+ } elsif ( UNIVERSAL::isa( $value, 'SCALAR' ) ) {
+ return $$value;
+ }
+ }
+
+ return $m->interp->apply_escapes( $value, 'h' ) if $args{'Escape'};
+ return $value;
+}
+
+
1;