%# BEGIN BPS TAGGED BLOCK {{{ %# %# COPYRIGHT: %# %# This software is Copyright (c) 1996-2018 Best Practical Solutions, LLC %# %# %# (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 }}} <& /Elements/Header, Title => $title &> <& /Elements/Tabs &> <& /Elements/ListActions, actions => \@results &>
% foreach my $var (qw(Query Format OrderBy Order Rows Page SavedSearchId SavedChartSearchId Token)) { %} <& /Elements/CollectionList, Query => $Query, DisplayFormat => $DisplayFormat, Format => $Format, Verbatim => 1, AllowSorting => 1, OrderBy => $OrderBy, Order => $Order, Rows => $Rows, Page => $Page, BaseURL => RT->Config->Get('WebPath')."/Search/Bulk.html?", Class => 'RT::Tickets' &> % $m->callback(CallbackName => 'AfterTicketList', ARGSRef => \%ARGS);
<& /Elements/Submit, Label => loc('Update'), CheckboxNameRegex => '/^UpdateTicket(All)?$/', CheckAll => 1, ClearAll => 1 &>
<&|/Widgets/TitleBox, title => $title &>
<&|/l&>Make Owner: <& /Elements/SelectOwner, Name => "Owner", Default => $ARGS{Owner} || '' &>
<&|/l&>Add Requestor: <& /Elements/EmailInput, Name => "AddRequestor", Size=> 20, Default => $ARGS{AddRequestor} &>
<&|/l&>Remove Requestor: <& /Elements/EmailInput, Name => "DeleteRequestor", Size=> 20, Default => $ARGS{DeleteRequestor} &>
<&|/l&>Add Cc: <& /Elements/EmailInput, Name => "AddCc", Size=> 20, Default => $ARGS{AddCc} &>
<&|/l&>Remove Cc: <& /Elements/EmailInput, Name => "DeleteCc", Size=> 20, Default => $ARGS{DeleteCc} &>
<&|/l&>Add AdminCc: <& /Elements/EmailInput, Name => "AddAdminCc", Size=> 20, Default => $ARGS{AddAdminCc} &>
<&|/l&>Remove AdminCc: <& /Elements/EmailInput, Name => "DeleteAdminCc", Size=> 20, Default => $ARGS{DeleteAdminCc} &>
% my $rel = ($ARGS{Priority} =~ s/^R//);
<&|/l&>Make subject:
<&|/l&>Make priority: <& /Elements/SelectPriority, Name => "Priority", Default => $ARGS{Priority} &>
<&|/l&>Make queue: <& /Elements/SelectQueue, Name => "Queue", Default => $ARGS{Queue} &>
<&|/l&>Make Status: <& /Ticket/Elements/SelectStatus, Name => "Status", Default => $ARGS{Status}, Queues => $seen_queues &>
<&|/l&>Make date Starts: <& /Elements/SelectDate, Name => "Starts_Date", Default => $ARGS{Starts_Date} || '' &>
<&|/l&>Make date Started: <& /Elements/SelectDate, Name => "Started_Date", Default => $ARGS{Started_Date} || '' &>
<&|/l&>Make date Told: <& /Elements/SelectDate, Name => "Told_Date", Default => $ARGS{Told_Date} || '' &>
<&|/l&>Make date Due: <& /Elements/SelectDate, Name => "Due_Date", Default => $ARGS{Due_Date} || '' &>
<&| /Widgets/TitleBox, title => loc('Add comments or replies to selected tickets') &> % $m->callback( CallbackName => 'BeforeTransactionCustomFields', CustomFields => $TxnCFs ); % while (my $CF = $TxnCFs->Next()) { % } # end if while <& /Ticket/Elements/AddAttachments, %ARGS &>
<&|/l&>Update Type:
<&|/l&>Subject: " /> % $m->callback( %ARGS, CallbackName => 'AfterUpdateSubject' );
<% $CF->Name %>: <& /Elements/EditCustomField, CustomField => $CF, Object => RT::Transaction->new( $session{'CurrentUser'} ), &><% $CF->FriendlyType %>
<&|/l&>Message: % $m->callback( %ARGS, CallbackName => 'BeforeMessageBox' ); %# Currently, bulk update always starts with Comment not Reply selected, so we check this unconditionally % my $IncludeSignature = RT->Config->Get('MessageBoxIncludeSignatureOnComment'); <& /Elements/MessageBox, Name => "UpdateContent", $ARGS{UpdateContent} ? ( Default => $ARGS{UpdateContent}, IncludeSignature => 0 ) : ( IncludeSignature => $IncludeSignature ), &>
<%perl> my $cfs = RT::CustomFields->new($session{'CurrentUser'}); $cfs->LimitToGlobal(); $cfs->LimitToQueue($_) for keys %$seen_queues; $cfs->SetContextObject( values %$seen_queues ) if keys %$seen_queues == 1; % if ( $cfs->Count ) { <&|/Widgets/TitleBox, title => loc('Edit Custom Fields') &> <& /Elements/BulkCustomFields, $ARGS{'AddMoreAttach'} ? %ARGS : (), CustomFields => $cfs &> % } <&|/Widgets/TitleBox, title => loc('Edit Links'), color => "#336633"&> <&|/l&>Enter tickets or URIs to link tickets to. Separate multiple entries with spaces.
<& /Elements/BulkLinks, Collection => $Tickets, $ARGS{'AddMoreAttach'} ? %ARGS : () &> <&| /Widgets/TitleBox, title => loc('Merge'), color => '#336633' &> <& /Ticket/Elements/EditMerge, Tickets => $Tickets, %ARGS &> <& /Elements/Submit, Label => loc('Update') &>
<%INIT> unless ( defined $Rows ) { $Rows = $RowsPerPage; $ARGS{Rows} = $RowsPerPage; } my $title = loc("Update multiple tickets"); #freeside unless ( $session{'CurrentUser'} ->HasRight( Right => 'BulkUpdateTickets', Object => RT->System) ) { Abort('You are not allowed to bulk-update tickets.'); } # Iterate through the ARGS hash and remove anything with a null value. map ( $ARGS{$_} =~ /^$/ && ( delete $ARGS{$_} ), keys %ARGS ); my (@results); ProcessAttachments(ARGSRef => \%ARGS); $Page ||= 1; $Format ||= RT->Config->Get('DefaultSearchResultFormat'); # inject _CHECKBOX to the first field. my $DisplayFormat = "'__CheckBox.{UpdateTicket}__',". $Format; $DisplayFormat =~ s/\s*,\s*('?__NEWLINE__'?)/,$1,''/gi; $DECODED_ARGS->{'UpdateTicketAll'} = 1 unless @UpdateTicket; my $Tickets = RT::Tickets->new( $session{'CurrentUser'} ); $Tickets->FromSQL($Query); if ( $OrderBy =~ /\|/ ) { # Multiple Sorts my @OrderBy = split /\|/, $OrderBy; my @Order = split /\|/, $Order; $Tickets->OrderByCols( map { { FIELD => $OrderBy[$_], ORDER => $Order[$_] } } ( 0 .. $#OrderBy ) ); } else { $Tickets->OrderBy( FIELD => $OrderBy, ORDER => $Order ); } $Tickets->RowsPerPage($Rows) if ($Rows); $Tickets->GotoPage( $Page - 1 ); # SB uses page 0 as the first page Abort( loc("No search to operate on.") ) unless ($Tickets); # build up a list of all custom fields for tickets that we're displaying, so # we can display sane edit widgets. my $fields = {}; my $seen_queues = {}; while ( my $ticket = $Tickets->Next ) { next if $seen_queues->{ $ticket->Queue }; $seen_queues->{ $ticket->Queue } ||= $ticket->QueueObj; my $custom_fields = $ticket->CustomFields; while ( my $field = $custom_fields->Next ) { $fields->{ $field->id } = $field; } } #Iterate through each ticket we've been handed my @linkresults; $Tickets->RedoSearch(); if ( defined($ARGS{'Priority'}) and ($ARGS{'Priority-Mode'} || '') eq 'relative' ) { # magic in Ticket::SetPriority $ARGS{'Priority'} = 'R'.$ARGS{'Priority'}; } delete $ARGS{'Priority-Mode'}; unless ( $ARGS{'AddMoreAttach'} ) { while ( my $Ticket = $Tickets->Next ) { my $tid = $Ticket->id; next unless grep $tid == $_, @UpdateTicket; #Update the links $ARGS{'id'} = $Ticket->id; my @updateresults = ProcessUpdateMessage( TicketObj => $Ticket, ARGSRef => \%ARGS, KeepAttachments => 1, ); #Update the basics. my @basicresults = ProcessTicketBasics( TicketObj => $Ticket, ARGSRef => \%ARGS ); my @dateresults = ProcessTicketDates( TicketObj => $Ticket, ARGSRef => \%ARGS ); #Update the watchers my @watchresults = ProcessTicketWatchers( TicketObj => $Ticket, ARGSRef => \%ARGS ); @linkresults = ProcessTicketLinks( TicketObj => $Ticket, TicketId => 'Ticket', ARGSRef => \%ARGS ); my @cfresults = ProcessRecordBulkCustomFields( RecordObj => $Ticket, ARGSRef => \%ARGS ); my @statusresults = ProcessTicketStatus( TicketObj => $Ticket, ARGSRef => \%ARGS ); my @tempresults = ( @watchresults, @basicresults, @dateresults, @updateresults, @linkresults, @cfresults, @statusresults ); @tempresults = map { $_ =~ /^Ticket \d+:/ ? $_ : loc( "Ticket [_1]: [_2]", $Ticket->Id, $_ ) } @tempresults; @results = ( @results, @tempresults ); } delete $session{'Attachments'}{ $ARGS{'Token'} }; $Tickets->RedoSearch(); } my $TxnCFs = RT::CustomFields->new( $session{CurrentUser} ); $TxnCFs->LimitToLookupType( RT::Transaction->CustomFieldLookupType ); $TxnCFs->LimitToGlobalOrObjectId( keys %$seen_queues ); $TxnCFs->SetContextObject( values %$seen_queues ) if keys %$seen_queues == 1; <%args> $Format => undef $Page => 1 $Rows => undef $RowsPerPage => undef $Order => 'ASC' $OrderBy => 'id' $Query => undef @UpdateTicket => ()