diff options
author | Ivan Kohler <ivan@freeside.biz> | 2014-09-15 20:44:48 -0700 |
---|---|---|
committer | Ivan Kohler <ivan@freeside.biz> | 2014-09-15 20:59:00 -0700 |
commit | 5b3efac57771fbc37874a3dd39d3df835cdd6133 (patch) | |
tree | f653976031646a27771f39902ed9296a4c129f30 /rt/share | |
parent | 008524b8e963831999983769f7fec11f55a72f16 (diff) |
RT 4.0.22
Diffstat (limited to 'rt/share')
38 files changed, 2080 insertions, 56 deletions
diff --git a/rt/share/html/Admin/Users/Modify.html b/rt/share/html/Admin/Users/Modify.html index 814e7f996..2483e5b7f 100755 --- a/rt/share/html/Admin/Users/Modify.html +++ b/rt/share/html/Admin/Users/Modify.html @@ -109,7 +109,7 @@ <&| /Widgets/TitleBox, title => loc('Access control') &> <input type="hidden" class="hidden" name="SetEnabled" value="1" /> -<input type="checkbox" class="checkbox" name="Enabled" value="1" <%$EnabledChecked%> /> +<input type="checkbox" class="checkbox" name="Enabled" value="1" <%$EnabledChecked||''%> /> <&|/l&>Let this user access RT</&><br /> diff --git a/rt/share/html/Admin/Users/Modify.html.orig b/rt/share/html/Admin/Users/Modify.html.orig new file mode 100755 index 000000000..814e7f996 --- /dev/null +++ b/rt/share/html/Admin/Users/Modify.html.orig @@ -0,0 +1,421 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC +%# <sales@bestpractical.com> +%# +%# (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 }}} +<& /Admin/Elements/Header, Title => $title &> +<& /Elements/Tabs &> + +<& /Elements/ListActions, actions => \@results &> + +<form action="<%RT->Config->Get('WebPath')%>/Admin/Users/Modify.html" method="post" enctype="multipart/form-data"> +%if ($Create) { +<input type="hidden" class="hidden" name="id" value="new" /> +% } else { +<input type="hidden" class="hidden" name="id" value="<%$UserObj->Id%>" /> +% } +<table width="100%" border="0"> +<tr> + +<td valign="top" class="boxcontainer"> +<&| /Widgets/TitleBox, title => loc('Identity') &> + +<table> +<tr><td align="right"> +<&|/l&>Username</&>: +</td><td> +<input name="Name" value="<%$UserObj->Name||$Name||''%>" /> <strong><&|/l&>(required)</&></strong> +</td></tr> +<tr><td align="right"> +<&|/l&>Email</&>: +</td><td> +<input name="EmailAddress" value="<%$UserObj->EmailAddress||$EmailAddress||''%>" /> +</td></tr> +<tr><td align="right"> +<&|/l&>Real Name</&>: +</td><td> +<input name="RealName" value="<%$UserObj->RealName||$RealName||''%>" /> +</td></tr> +<tr><td align="right"> +<&|/l&>Nickname</&>: +</td><td> +<input name="NickName" value="<%$UserObj->NickName||$NickName||''%>" /> +</td></tr> +<tr><td align="right"> +<&|/l&>Unix login</&>: +</td><td> +<input name="Gecos" value="<%$UserObj->Gecos||$Gecos||''%>" /> +</td></tr> +<tr><td align="right"> +<&|/l&>Language</&>: +</td><td> +<& /Elements/SelectLang, Name => 'Lang', Default => $UserObj->Lang||$Lang &> +</td></tr> +<tr><td align="right"> +<&|/l&>Extra info</&>: +</td><td> +<textarea name="FreeformContactInfo" cols="20" rows="5"><%$UserObj->FreeformContactInfo||$FreeformContactInfo||''%></textarea> +</td></tr> +</table> +</&> +<br /> + +<&| /Widgets/TitleBox, title => loc('Customers') &> +<& /Elements/EditCustomers, Object => $UserObj, CustomerString=> $CustomerString, ServiceString => $ServiceString &> +</&> +<br /> + +<&| /Widgets/TitleBox, title => loc('Access control') &> +<input type="hidden" class="hidden" name="SetEnabled" value="1" /> +<input type="checkbox" class="checkbox" name="Enabled" value="1" <%$EnabledChecked%> /> +<&|/l&>Let this user access RT</&><br /> + + +<input type="hidden" class="hidden" name="SetPrivileged" value="1" /> +<input type="checkbox" class="checkbox" name="Privileged" value="1" <%$PrivilegedChecked||''%> /> <&|/l&>Let this user be granted rights</&> (<&|/l&>Privileged</&>)<br /> + +<& /Elements/EditPassword, + User => $UserObj, + Name => [qw(CurrentPass Pass1 Pass2)], +&> +</&> +% $m->callback( %ARGS, CallbackName => 'LeftColumnBottom', UserObj => $UserObj ); +</td> + +<td valign="top" class="boxcontainer"> +<&| /Widgets/TitleBox, title => loc('Location') &> +<table> +<tr><td align="right"> +<&|/l&>Organization</&>: +</td><td> +<input name="Organization" value="<%$UserObj->Organization||$Organization||''%>" /> +</td></tr> +<tr><td align="right"> +<&|/l&>Address1</&>: +</td><td> +<input name="Address1" value="<%$UserObj->Address1||$Address1||''%>" /> +</td></tr> +<tr><td align="right"> +<&|/l&>Address2</&>: +</td><td> +<input name="Address2" value="<%$UserObj->Address2||$Address2||''%>" /> +</td></tr> +<tr><td align="right"> +<&|/l&>City</&>: +</td><td> +<input name="City" value="<%$UserObj->City||$City||''%>" size="14" /> + +</td></tr> +<tr><td align="right"> +<&|/l&>State</&>: +</td><td> +<input name="State" value="<%$UserObj->State||$State||''%>" size="3" /> + +</td></tr> +<tr><td align="right"> +<&|/l&>Zip</&>: +</td><td> +<input name="Zip" value="<%$UserObj->Zip||$Zip||''%>" size="9" /> +</td></tr> +<tr><td align="right"> +<&|/l&>Country</&>: +</td><td> +<input name="Country" value="<%$UserObj->Country||$Country||''%>" /> +</td></tr> +</table> +</&> +<br /> +<&| /Widgets/TitleBox, title => loc('Phone numbers') &> +<table> +<tr><td align="right"> +<&|/l&>Residence</&>: +</td><td> +<input name="HomePhone" value="<%$UserObj->HomePhone||$HomePhone||''%>" size="13" /><br /> +</td></tr> +<tr><td align="right"> +<&|/l&>Work</&>: +</td><td> +<input name="WorkPhone" value="<%$UserObj->WorkPhone||$WorkPhone||''%>" size="13" /><br /> +</td></tr> +<tr><td align="right"> +<&|/l&>Mobile</&>: +</td><td> +<input name="MobilePhone" value="<%$UserObj->MobilePhone||$MobilePhone||''%>" size="13" /><br /> +</td></tr> +<tr><td align="right"> +<&|/l&>Pager</&>: +</td><td> +<input name="PagerPhone" value="<%$UserObj->PagerPhone||$PagerPhone||''%>" size="13" /><br /> +</td> +</tr> +</table> +</&> +<br /> +<&| /Widgets/TitleBox, title => loc('Custom Fields') &> +<table> +% my $CFs = $UserObj->CustomFields; +% while (my $CF = $CFs->Next) { +<tr valign="top"><td align="right"> +<% loc($CF->Name) %>: +</td><td> +% if ($UserObj->id) { +<& /Elements/EditCustomField, %ARGS, Object => $UserObj, CustomField => $CF &> +% } else { +<& /Elements/EditCustomField, %ARGS, NamePrefix => 'Object-RT::User--CustomField-', CustomField => $CF &> +% } +</td></tr> +% } +</table> +</&> +% $m->callback( %ARGS, CallbackName => 'RightColumnBottom', UserObj => $UserObj ); +</td></tr> +<tr> +<td colspan="2"> +<&| /Widgets/TitleBox, title => loc('Comments about this user') &> +<textarea class="comments" name="Comments" cols="80" rows="5" wrap="virtual"><%$UserObj->Comments||$Comments||''%></textarea> +</&> +%if (!$Create && $UserObj->Privileged) { +<br /> +<&| /Widgets/TitleBox, title => loc('Signature') &> +<textarea class="signature" cols="80" rows="5" name="Signature" wrap="hard"><%$UserObj->Signature||$Signature||''%></textarea> +</&> +% } + +</td> +</tr> +</table> + +% if ( $Create ) { +<& /Elements/Submit, Label => loc('Create') &> +% } else { +<& /Elements/Submit, Label => loc('Save Changes') &> +% } +</form> + +<%INIT> + +my $UserObj = RT::User->new($session{'CurrentUser'}); +my ($title, $PrivilegedChecked, $EnabledChecked, $Disabled, $result, @results); + +my ($val, $msg); + +if ($Create) { + $title = loc("Create a new user"); +} +else { + + if ( defined $id && $id eq 'new') { + ( $val, $msg ) = $UserObj->Create( + Name => $Name, + EmailAddress => $ARGS{'EmailAddress'}, + Name => $ARGS{'Name'}, + Comments => $ARGS{'Comments'}, + Signature => $ARGS{'Signature'}, + EmailAddress => $ARGS{'EmailAddress'}, + FreeformContactInfo => $ARGS{'FreeformContactInfo'}, + Organization => $ARGS{'Organization'}, + RealName => $ARGS{'RealName'}, + NickName => $ARGS{'NickName'}, + Lang => $ARGS{'Lang'}, + EmailEncoding => $ARGS{'EmailEncoding'}, + WebEncoding => $ARGS{'WebEncoding'}, + ExternalContactInfoId => $ARGS{'ExternalContactInfoId'}, + ContactInfoSystem => $ARGS{'ContactInfoSystem'}, + Gecos => $ARGS{'Gecos'}, + ExternalAuthId => $ARGS{'ExternalAuthId'}, + AuthSystem => $ARGS{'AuthSystem'}, + HomePhone => $ARGS{'HomePhone'}, + WorkPhone => $ARGS{'WorkPhone'}, + MobilePhone => $ARGS{'MobilePhone'}, + PagerPhone => $ARGS{'PagerPhone'}, + Address1 => $ARGS{'Address1'}, + Address2 => $ARGS{'Address2'}, + City => $ARGS{'City'}, + State => $ARGS{'State'}, + Zip => $ARGS{'Zip'}, + Country => $ARGS{'Country'}, + Privileged => $ARGS{'Privileged'}, + Disabled => ($ARGS{'Enabled'} ? 0 : 1) + ); + + if ($val) { + push @results, $msg; + push @results, ProcessObjectCustomFieldUpdates( ARGSRef => \%ARGS, Object => $UserObj ); + } else { + push @results, loc('User could not be created: [_1]', $msg); + } + } else { + $UserObj->Load($id) || $UserObj->Load($Name) + || Abort("Couldn't load user '" . ( $Name || '') . "'"); + $val = $UserObj->Id(); + } + + if ($val) { + $title = loc("Modify the user [_1]", $UserObj->Name); + } + + # If the create failed + else { + $title = loc("Create a new user"); + $Create = 1; + } +} + + +$m->callback( %ARGS, CallbackName => 'BeforeUpdate', User => $UserObj, ARGSRef => \%ARGS, Results => \@results ); + + +# If we have a user to modify, lets try. +if ($UserObj->Id && $id ne 'new') { + + my @fields = qw(Name Comments Signature EmailAddress FreeformContactInfo + Organization RealName NickName Lang EmailEncoding WebEncoding + ExternalContactInfoId ContactInfoSystem Gecos ExternalAuthId + AuthSystem HomePhone WorkPhone MobilePhone PagerPhone Address1 + Address2 City State Zip Country + ); + + my @fieldresults = UpdateRecordObject ( AttributesRef => \@fields, + Object => $UserObj, + ARGSRef => \%ARGS ); + push (@results,@fieldresults); + push @results, ProcessObjectCustomFieldUpdates( ARGSRef => \%ARGS, Object => $UserObj ); + + #deal with freeside customer links + push @results, ProcessObjectCustomers( ARGSRef => \%ARGS, Object => $UserObj ); + + # {{{ Deal with special fields: Privileged, Enabled + if ( $SetPrivileged and $Privileged != $UserObj->Privileged ) { + my ($code, $msg) = $UserObj->SetPrivileged($Privileged); + push @results, loc('Privileged status: [_1]', loc_fuzzy($msg)); + } + + #we're asking about enabled on the web page but really care about disabled. + $Disabled = $Enabled ? 0 : 1; + + if ( ($SetEnabled) and ( $Disabled != $UserObj->Disabled) ) { + my ($code, $msg) = $UserObj->SetDisabled($Disabled); + push @results, $msg; + } + + +} + + +my %password_cond = $UserObj->CurrentUserRequireToSetPassword; +if ( $UserObj->Id ) { + # Deal with Password field + my ($status, $msg) = $UserObj->SafeSetPassword( + Current => $CurrentPass, + New => $Pass1, + Confirmation => $Pass2, + ); + push @results, $msg; + + if ( $id eq 'new' && !$status ) { + push @results, loc("A password was not set, so user won't be able to login."); + } +} + + +# Do some setup for the ui +unless ( $UserObj->id && $UserObj->Disabled ) { + $EnabledChecked = 'checked="checked"'; +} + +if ((!$Create && $UserObj->Privileged()) or (!$UserObj->Id and $Privileged)) { + $PrivilegedChecked = 'checked="checked"'; +} + +# This code does automatic redirection if any updates happen. +MaybeRedirectForResults( + Actions => \@results, + Arguments => { id => $UserObj->Id }, +) if $UserObj->Id; + +</%INIT> + + +<%ARGS> +$id => undef +$Name => undef +$Comments => undef +$Signature => undef +$EmailAddress => undef +$FreeformContactInfo => undef +$Organization => undef +$RealName => undef +$NickName => undef +$Privileged => undef +$SetPrivileged => undef +$Enabled => undef +$SetEnabled => undef +$Lang => undef +$EmailEncoding => undef +$WebEncoding => undef +$ExternalContactInfoId => undef +$ContactInfoSystem => undef +$Gecos => undef +$ExternalAuthId => undef +$AuthSystem => undef +$HomePhone => undef +$WorkPhone => undef +$MobilePhone => undef +$PagerPhone => undef +$Address1 => undef +$Address2 => undef +$City => undef +$State => undef +$Zip => undef +$Country => undef +$CurrentPass => undef +$Pass1 => undef +$Pass2 => undef +$Create=> undef +$OnlySearchForCustomers => undef +$OnlySearchForServices => undef +$CustomerString => undef +$ServiceString => undef +</%ARGS> diff --git a/rt/share/html/Approvals/index.html b/rt/share/html/Approvals/index.html index 97f360ac0..dbdc11ec5 100755 --- a/rt/share/html/Approvals/index.html +++ b/rt/share/html/Approvals/index.html @@ -72,12 +72,9 @@ foreach my $arg ( keys %ARGS ) { next if $skip_update; if ( $ARGS{ "Approval-" . $ticket->Id . "-Notes" } ) { - my $notes = MIME::Entity->build( - Data => [ $ARGS{ "Approval-" . $ticket->Id . "-Notes" } ] - ); - RT::I18N::SetMIMEEntityToUTF8($notes); # convert text parts into utf-8 - - my ( $notesval, $notesmsg ) = $ticket->Correspond( MIMEObj => $notes ); + my ( $notesval, $notesmsg ) = $ticket->Correspond( + Content => $ARGS{ "Approval-" . $ticket->Id . "-Notes" } + ); if ($notesval) { push ( @actions, loc("Approval #[_1]: Notes recorded",$ticket->Id )); } else { diff --git a/rt/share/html/Elements/.CalendarDaySchedule.swp b/rt/share/html/Elements/.CalendarDaySchedule.swp Binary files differnew file mode 100644 index 000000000..f79cd0938 --- /dev/null +++ b/rt/share/html/Elements/.CalendarDaySchedule.swp diff --git a/rt/share/html/Elements/.CalendarEventWeekly.swp b/rt/share/html/Elements/.CalendarEventWeekly.swp Binary files differnew file mode 100644 index 000000000..af6c22220 --- /dev/null +++ b/rt/share/html/Elements/.CalendarEventWeekly.swp diff --git a/rt/share/html/Elements/.CalendarSlotSchedule.swp b/rt/share/html/Elements/.CalendarSlotSchedule.swp Binary files differnew file mode 100644 index 000000000..6b8a8f9c2 --- /dev/null +++ b/rt/share/html/Elements/.CalendarSlotSchedule.swp diff --git a/rt/share/html/Elements/CalendarSlotSchedule.dynamic b/rt/share/html/Elements/CalendarSlotSchedule.dynamic new file mode 100644 index 000000000..88202d417 --- /dev/null +++ b/rt/share/html/Elements/CalendarSlotSchedule.dynamic @@ -0,0 +1,93 @@ +<%ARGS> + $Date => undef, + @Tickets => () + $slots => $default_slots, + $sday => undef, + $tod_row => undef, + $timestep => $default_timestep, + @username => () +</%ARGS> +<%SHARED> +my @slots = ( [], [], [], [], [], [], [] ); +</%SHARED> +% #for my $t ( @{ $Tickets{$date->strftime("%F")} } ) { +% for my $t (@Tickets) { +% +% my($sm, $sh) = ($t->StartsObj->Localtime('user'))[1,2]; +% my $starts = $sh*60 + $sm; +% +% if ( RTx::Calendar::LocalDate($t->StartsObj->Unix) eq $Date->strftime('%F') #today +% && $starts >= $tod_row && $starts < ($tod_row + $timestep) ) { +% #then we're a new entry, find a slot for us +% my $s = 0; +% while ( ref($slots[$sday]->[$s]) ) { $s++ } +% $slots[$sday]->[$s] = [ $t->Id, $t ]; +% } +% +% my($dm, $dh) = ($t->DueObj->Localtime('user'))[1,2]; +% my $due = $dh*60 + $dm; +% +% if ( RTx::Calendar::LocalDate($t->DueObj->Unix) eq $Date->strftime('%F') #today +% && $due <= $tod_row && $due > ($tod_row + $timestep ) ) { +% #then find our slot and remove us +% @{ $slots[$sday] } = +% map { (!ref($_) || $_->[0] != $t->Id) ? $_ : '' } +% @{ $slots[$sday] }; +% } +% +% } +% +% pop @{ $slots[$sday] } while @{ $slots[$sday] } && !ref($slots[$sday]->[-1]); +% +% #now display: +% +% if ( scalar(@{$slots[$sday]}) > $slots ) { +% #overflow situation, eek... could be handled better, how? + + <td colspan=<%$slots%> + class="weekly +%# <% $is_today ? 'today' +%# : $is_yesterday ? 'yesterday' +%# : $is_aweekago ? 'aweekago' +%# : '' +%# %> + " + >MULTIPLE + </td> + +% } else { +% +% foreach my $slot ( @{ $slots[$sday] } ) { +% my( $id, $ticket ) = @$slot; + + <td class="weekly +%# <% $is_today ? 'today' +%# : $is_yesterday ? 'yesterday' +%# : $is_aweekago ? 'aweekago' +%# : '' +%# %> + " + ><% $id %> + </td> + +% } +% +% if ( scalar(@{$slots[$sday]}) < $slots ) { + + <td colspan=<% $slots - scalar(@{$slots[$sday]}) %> + class="weekly +%# <% $is_today ? 'today' +%# : $is_yesterday ? 'yesterday' +%# : $is_aweekago ? 'aweekago' +%# : '' +%# %> + " + > + </td> +% } +% +% } +<%ONCE> +my $default_slots = RT->Config->Get('CalendarWeeklySlots') || 5; +my $default_timestep = RT->Config->Get('CalendarWeeklySizeMin') || 30; #1/2h +</%ONCE> diff --git a/rt/share/html/Elements/EditCustomFieldDate b/rt/share/html/Elements/EditCustomFieldDate index f62f04704..c430b0b33 100644 --- a/rt/share/html/Elements/EditCustomFieldDate +++ b/rt/share/html/Elements/EditCustomFieldDate @@ -46,7 +46,7 @@ %# %# END BPS TAGGED BLOCK }}} % my $name = $NamePrefix.$CustomField->Id.'-Values'; -<& /Elements/SelectDate, Name => "$name", current => 0, ShowTime => 0 &> (<%$DateObj->AsString(Time => 0, Timezone => 'utc')%>) +<& /Elements/SelectDate, Name => "$name", current => 0, ShowTime => 0, $KeepValue && $Default ? (Default => $Default) : () &> (<%$DateObj->AsString(Time => 0, Timezone => 'utc')%>) <%INIT> my $DateObj = RT::Date->new ( $session{'CurrentUser'} ); @@ -59,4 +59,5 @@ $NamePrefix => undef $Default => undef $Values => undef $MaxValues => 1 +$KeepValue => undef </%ARGS> diff --git a/rt/share/html/Elements/EditCustomFieldDateTime b/rt/share/html/Elements/EditCustomFieldDateTime index edf125e80..b50ea431a 100644 --- a/rt/share/html/Elements/EditCustomFieldDateTime +++ b/rt/share/html/Elements/EditCustomFieldDateTime @@ -46,7 +46,7 @@ %# %# END BPS TAGGED BLOCK }}} % my $name = $NamePrefix.$CustomField->Id.'-Values'; -<& /Elements/SelectDate, Name => "$name", current => 0 &> (<%$DateObj->AsString%>) +<& /Elements/SelectDate, Name => "$name", current => 0, $KeepValue && $Default ? (Default => $Default) : () &> (<%$DateObj->AsString($KeepValue ? ( Timezone => 'utc' ) : () )%>) <%INIT> my $DateObj = RT::Date->new ( $session{'CurrentUser'} ); @@ -60,4 +60,5 @@ $Default => undef $Values => undef $MaxValues => 1 $Format => 'ISO' +$KeepValue => undef </%ARGS> diff --git a/rt/share/html/Elements/Error b/rt/share/html/Elements/Error index b2042610e..d747c4e5b 100755 --- a/rt/share/html/Elements/Error +++ b/rt/share/html/Elements/Error @@ -78,11 +78,7 @@ $SuppressHeader => 0, my $error = "WebRT: $Why"; $error .= " ($Details)" if defined $Details && length $Details; -# TODO: Log::Dispatch isn't UTF-8 safe. Autrijus needs to talk to dave rolsky about getting this fixed -use Encode (); -Encode::_utf8_off($error); - -$RT::Logger->error($error); +$RT::Logger->error( $error ); if ( $session{'REST'} ) { $r->content_type('text/plain'); diff --git a/rt/share/html/NoAuth/css/.calendar.css.swp b/rt/share/html/NoAuth/css/.calendar.css.swp Binary files differnew file mode 100644 index 000000000..cbc46cd5e --- /dev/null +++ b/rt/share/html/NoAuth/css/.calendar.css.swp diff --git a/rt/share/html/NoAuth/css/aileron/ticket.css b/rt/share/html/NoAuth/css/aileron/ticket.css index 0d60f6ada..bc6315001 100644 --- a/rt/share/html/NoAuth/css/aileron/ticket.css +++ b/rt/share/html/NoAuth/css/aileron/ticket.css @@ -223,22 +223,6 @@ div#ticket-history .messagebody .messagebody{ .ticket-summary .titlebox-title .left a, .ticket-summary .titlebox-title .left a:visited { color: #fff;} -.unread-messages .titlebox , .unread-messages .titlebox-title .left { - border: 1px solid #99a; - border-right: 2px solid #aab; - border-bottom: 2px solid #aab; - -} - - -.unread-messages .titlebox { - background-color: #dde; -} - -.unread-messages .titlebox-title .left { - background-color: #cce; -} - .ticket-inactive { text-decoration: line-through; color: #666 diff --git a/rt/share/html/NoAuth/css/base/ticket.css b/rt/share/html/NoAuth/css/base/ticket.css index 6a43a1db1..d30b04645 100644 --- a/rt/share/html/NoAuth/css/base/ticket.css +++ b/rt/share/html/NoAuth/css/base/ticket.css @@ -143,4 +143,7 @@ display: none; } +.unread-messages .titlebox-content :link { + text-decoration: underline; +} diff --git a/rt/share/html/NoAuth/iCal/dhandler b/rt/share/html/NoAuth/iCal/dhandler index 35da94080..46c272921 100644 --- a/rt/share/html/NoAuth/iCal/dhandler +++ b/rt/share/html/NoAuth/iCal/dhandler @@ -48,7 +48,6 @@ <%init> use Data::ICal; use Data::ICal::Entry::Event; -use Encode (); my $path = $m->dhandler_arg; @@ -62,8 +61,8 @@ $notfound->() unless $path =~ m!^([^/]+)/([^/]+)/(.*)(\.(ical|ics))?!; my ($name, $auth, $search) = ($1, $2, $3); # Unescape parts $_ =~ s/\%([0-9a-z]{2})/chr(hex($1))/gei for $name, $search; -# convert to perl strings -$_ = Encode::decode_utf8( $_ ) for $name, $search; +# Decode from bytes to characters +$_ = Encode::decode( "UTF-8", $_ ) for $name, $search; my $user = RT::User->new( RT->SystemUser ); $user->Load( $name ); diff --git a/rt/share/html/NoAuth/images/week-collapse.xcf b/rt/share/html/NoAuth/images/week-collapse.xcf Binary files differnew file mode 100644 index 000000000..cbb2b95eb --- /dev/null +++ b/rt/share/html/NoAuth/images/week-collapse.xcf diff --git a/rt/share/html/NoAuth/images/week-expand.xcf b/rt/share/html/NoAuth/images/week-expand.xcf Binary files differnew file mode 100644 index 000000000..1ab8e65c8 --- /dev/null +++ b/rt/share/html/NoAuth/images/week-expand.xcf diff --git a/rt/share/html/REST/1.0/Forms/ticket/comment b/rt/share/html/REST/1.0/Forms/ticket/comment index 934cbfb68..41320ba4c 100755 --- a/rt/share/html/REST/1.0/Forms/ticket/comment +++ b/rt/share/html/REST/1.0/Forms/ticket/comment @@ -91,8 +91,9 @@ my $ent = MIME::Entity->build( 'X-RT-Interface' => 'REST', ); $ent->attach( - 'Content-Type' => $changes{'Content-Type'} || 'text/plain', - Data => $changes{Text}, + Type => $changes{'Content-Type'} || 'text/plain', + Charset => "UTF-8", + Data => Encode::encode("UTF-8", $changes{Text} ), ) if $changes{Text}; diff --git a/rt/share/html/REST/1.0/Forms/ticket/default b/rt/share/html/REST/1.0/Forms/ticket/default index 2a0c7efa4..33a8935d6 100755 --- a/rt/share/html/REST/1.0/Forms/ticket/default +++ b/rt/share/html/REST/1.0/Forms/ticket/default @@ -191,13 +191,14 @@ else { $v{MIMEObj} = MIME::Entity->build( Type => "multipart/mixed", - From => $session{CurrentUser}->EmailAddress, - Subject => $v{Subject}, + From => Encode::encode( "UTF-8", $session{CurrentUser}->EmailAddress ), + Subject => Encode::encode( "UTF-8", $v{Subject}), 'X-RT-Interface' => 'REST', ); $v{MIMEObj}->attach( - Data => $text, - 'Content-Type' => $v{'Content-Type'} || 'text/plain', + Type => $v{'Content-Type'} || 'text/plain', + Charset => "UTF-8", + Data => Encode::encode( "UTF-8", $text ), ) if $text; my ($status, $msg) = process_attachments($v{'MIMEObj'}, @atts); unless ($status) { diff --git a/rt/share/html/REST/1.0/ticket/comment b/rt/share/html/REST/1.0/ticket/comment index 4c058b6ab..177690d6a 100755 --- a/rt/share/html/REST/1.0/ticket/comment +++ b/rt/share/html/REST/1.0/ticket/comment @@ -108,7 +108,11 @@ my $ent = MIME::Entity->build( Type => "multipart/mixed", 'X-RT-Interface' => 'REST', ); -$ent->attach(Data => $k->{Text}) if $k->{Text}; +$ent->attach( + Type => "text/plain", + Charset => "UTF-8", + Data => Encode::encode( "UTF-8", $k->{Text} ), +) if $k->{Text}; { my ($res, $msg) = process_attachments($ent, @atts); diff --git a/rt/share/html/Schedule/.UserBar.swp b/rt/share/html/Schedule/.UserBar.swp Binary files differnew file mode 100644 index 000000000..0dcd4315e --- /dev/null +++ b/rt/share/html/Schedule/.UserBar.swp diff --git a/rt/share/html/Search/.Calendar.html.swp b/rt/share/html/Search/.Calendar.html.swp Binary files differnew file mode 100644 index 000000000..3e3788220 --- /dev/null +++ b/rt/share/html/Search/.Calendar.html.swp diff --git a/rt/share/html/Search/.Schedule.html.swp b/rt/share/html/Search/.Schedule.html.swp Binary files differnew file mode 100644 index 000000000..e88b29135 --- /dev/null +++ b/rt/share/html/Search/.Schedule.html.swp diff --git a/rt/share/html/Search/Bulk.html.orig b/rt/share/html/Search/Bulk.html.orig new file mode 100755 index 000000000..38ca64248 --- /dev/null +++ b/rt/share/html/Search/Bulk.html.orig @@ -0,0 +1,460 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC +%# <sales@bestpractical.com> +%# +%# (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 &> +<form method="post" action="<% RT->Config->Get('WebPath') %>/Search/Bulk.html" enctype="multipart/form-data" name="BulkUpdate" id="BulkUpdate"> +% foreach my $var (qw(Query Format OrderBy Order Rows Page SavedChartSearchId)) { +<input type="hidden" class="hidden" name="<%$var%>" value="<%$ARGS{$var} || ''%>" /> +%} +<& /Elements/CollectionList, + Query => $Query, + DisplayFormat => $Format, + Format => $ARGS{'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); + +<hr /> + +<& /Elements/Submit, Label => loc('Update'), CheckboxNameRegex => '/^UpdateTicket\d+$/', CheckAll => 1, ClearAll => 1 &> +<br /> +<&|/Widgets/TitleBox, title => $title &> +<table> +<tr> +<td valign="top"> +<table> +<tr><td class="label"> <&|/l&>Make Owner</&>: </td> +<td class="value"> <& /Elements/SelectOwner, Name => "Owner", Default => $ARGS{Owner} || '' &> +(<input type="checkbox" class="checkbox" name="ForceOwnerChange" + <% $ARGS{ForceOwnerChange} ? 'checked="checked"' : '' %> /> <&|/l&>Force change</&>) </td></tr> +<tr><td class="label"> <&|/l&>Add Requestor</&>: </td> +<td class="value"> <input name="AddRequestor" size="20" value="<% $ARGS{AddRequestor} || '' %>" /> </td></tr> +<tr><td class="label"> <&|/l&>Remove Requestor</&>: </td> +<td class="value"> <input name="DeleteRequestor" size="20" value="<% $ARGS{DeleteRequestor} || '' %>"/> </td></tr> +<tr><td class="label"> <&|/l&>Add Cc</&>: </td> +<td class="value"> <input name="AddCc" size="20" value="<% $ARGS{AddCc} || '' %>" /> </td></tr> +<tr><td class="label"> <&|/l&>Remove Cc</&>: </td> +<td class="value"> <input name="DeleteCc" size="20" value="<% $ARGS{DeleteCc} || '' %>" /> </td></tr> +<tr><td class="label"> <&|/l&>Add AdminCc</&>: </td> +<td class="value"> <input name="AddAdminCc" size="20" value="<% $ARGS{AddAdminCc} || '' %>" /> </td></tr> +<tr><td class="label"> <&|/l&>Remove AdminCc</&>: </td> +<td class="value"> <input name="DeleteAdminCc" size="20" value="<% $ARGS{DeleteAdminCc} || '' %>" /> </td></tr> +</table> +</td> +<td valign="top"> +<table> +<tr><td class="label"> <&|/l&>Make subject</&>: </td> +<td class="value"> <input name="Subject" size="20" value="<% $ARGS{Subject} || '' %>"/> </td></tr> +<tr><td class="label"> <&|/l&>Make priority</&>: </td> +% my $rel = ($ARGS{Priority} =~ s/^R//); +<td class="value"> <& /Elements/SelectPriority, Name => "Priority", Default => $ARGS{Priority} &> +<select name="Priority-Mode"> +<option value="absolute" <% !$rel && 'selected' %>>absolute</option> +<option value="relative" <% $rel && 'selected' %>>relative</option> +</select> +</td></tr> +<tr><td class="label"> <&|/l&>Make queue</&>: </td> +<td class="value"> <& /Elements/SelectQueue, Name => "Queue", Default => $ARGS{Queue} &> </td></tr> +<tr><td class="label"> <&|/l&>Make Status</&>: </td> +<td class="value"> <& /Elements/SelectStatus, Name => "Status", Default => $ARGS{Status}, Queues => $seen_queues &> </td></tr> +<tr><td class="label"> <&|/l&>Make date Starts</&>: </td> +<td class="value"> <& /Elements/SelectDate, Name => "Starts_Date", Default => $ARGS{Starts_Date} || '' &> </td></tr> +<tr><td class="label"> <&|/l&>Make date Started</&>: </td> +<td class="value"> <& /Elements/SelectDate, Name => "Started_Date", Default => $ARGS{Started_Date} || '' &> </td></tr> +<tr><td class="label"> <&|/l&>Make date Told</&>: </td> +<td class="value"> <& /Elements/SelectDate, Name => "Told_Date", Default => $ARGS{Told_Date} || '' &> </td></tr> +<tr><td class="label"> <&|/l&>Make date Due</&>: </td> +<td class="value"> <& /Elements/SelectDate, Name => "Due_Date", Default => $ARGS{Due_Date} || '' &> </td></tr> +<tr><td class="label"> <&|/l&>Make date Resolved</&>: </td> +<td class="value"> <& /Elements/SelectDate, Name => "Resolved_Date", Default => $ARGS{Resolved_Date} || '' &> </td></tr> +</table> + +</td> +</tr> +</table> +</&> +<&| /Widgets/TitleBox, title => loc('Add comments or replies to selected tickets') &> +<table> +<tr><td align="right"><&|/l&>Update Type</&>:</td> +<td><select name="UpdateType"> + <option value="private" <% $ARGS{UpdateType} && $ARGS{UpdateType} eq 'private' ? 'selected="selected"' : '' %> ><&|/l&>Comments (Not sent to requestors)</&></option> +<option value="response" <% $ARGS{UpdateType} && $ARGS{UpdateType} eq 'response' ? 'selected="selected"' : '' %>><&|/l&>Reply to requestors</&></option> +</select> +</td></tr> +<tr><td align="right"><&|/l&>Subject</&>:</td><td> <input name="UpdateSubject" +size="60" value="<% $ARGS{UpdateSubject} || "" %>" /></td></tr> +% while (my $CF = $TxnCFs->Next()) { +<tr> +<td align="right"><% $CF->Name %>:</td> +<td><& /Elements/EditCustomField, + CustomField => $CF, + NamePrefix => "Object-RT::Transaction--CustomField-", + Default => $ARGS{"Object-RT::Transaction--CustomField-" . $CF->id . '-Values'} || + $ARGS{"Object-RT::Transaction--CustomField-" . $CF->id . '-Value'}, + &><em><% $CF->FriendlyType %></em></td> +</td></tr> +% } # end if while + +<& /Ticket/Elements/AddAttachments, %ARGS &> + + <tr><td class="labeltop"><&|/l&>Message</&>:</td><td> +%# 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 ), + &> + </td></tr> + </table> + +</&> + +<%perl> +my $cfs = RT::CustomFields->new($session{'CurrentUser'}); +$cfs->LimitToGlobal(); +$cfs->LimitToQueue($_) for keys %$seen_queues; +</%perl> + +% if ($cfs->Count) { +<&|/Widgets/TitleBox, title => loc('Edit Custom Fields'), color => "#336633"&> +<table> +<tr> +<th><&|/l&>Name</&></th> +<th><&|/l&>Add values</&></th> +<th><&|/l&>Delete values</&></th> +</tr> +% while (my $cf = $cfs->Next()) { +<tr> +<td class="label"><% loc($cf->Name) %><br /> +<em>(<%$cf->FriendlyType%>)</em></td> +% my $rows = 5; +% my $cf_id = $cf->id; +% my @add = (NamePrefix => 'Bulk-Add-CustomField-', CustomField => $cf, Rows => $rows, +% Multiple => ($cf->MaxValues ==1 ? 0 : 1) , Cols => 25, +% Default => $ARGS{"Bulk-Add-CustomField-$cf_id-Values"} || $ARGS{"Bulk-Add-CustomField-$cf_id-Value"}, ); +% my @del = (NamePrefix => 'Bulk-Delete-CustomField-', CustomField => $cf, +% Rows => $rows, Multiple => 1, Cols => 25, +% Default => $ARGS{"Bulk-Delete-CustomField-$cf_id-Values"} || $ARGS{"Bulk-Delete-CustomField-$cf_id-Value"}, ); +% if ($cf->Type eq 'Select') { +<td><& /Elements/EditCustomFieldSelect, @add &></td> +<td><& /Elements/EditCustomFieldSelect, @del &></td> +% } elsif ($cf->Type eq 'Combobox') { +<td><& /Elements/EditCustomFieldCombobox, @add &></td> +<td><& /Elements/EditCustomFieldCombobox, @del &></td> +% } elsif ($cf->Type eq 'Freeform') { +<td><& /Elements/EditCustomFieldFreeform, @add &></td> +<td><& /Elements/EditCustomFieldFreeform, @del &></td> +% } elsif ($cf->Type eq 'Text') { +<td><& /Elements/EditCustomFieldText, @add &></td> +<td> </td> +% } elsif ($cf->Type eq 'Date') { +<td><& /Elements/EditCustomFieldDate, @add, Default => undef &></td> +<td><& /Elements/EditCustomFieldDate, @del, Default => undef &></td> +% } elsif ($cf->Type eq 'DateTime') { +% # Pass datemanip format to prevent another tz date conversion +<td><& /Elements/EditCustomFieldDateTime, @add, Default => undef, Format => 'datemanip' &></td> +<td><& /Elements/EditCustomFieldDateTime, @del, Default => undef, Format => 'datemanip' &></td> +% } else { +% $RT::Logger->crit("Unknown CustomField type: " . $cf->Type); +% } +</tr> +% } +</table> +</&> +% } + +<&|/Widgets/TitleBox, title => loc('Edit Links'), color => "#336633"&> +<em><&|/l&>Enter tickets or URIs to link tickets to. Separate multiple entries with spaces.</&></em><br /> +<& /Ticket/Elements/BulkLinks, Tickets => $Tickets, $ARGS{'AddMoreAttach'} ? %ARGS : () &> +</&> + +<& /Elements/Submit, Label => loc('Update') &> + + +</form> + + +<%INIT> +unless ( defined $Rows ) { + $Rows = $RowsPerPage; + $ARGS{Rows} = $RowsPerPage; +} +my $title = loc("Update multiple 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. +$Format =~ s/'?([^']+)'?,/'___CHECKBOX__$1',/; #' + +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 }++; + + 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(); + +# pull out the labels for any custom fields we want to update + +my $cf_del_keys; +@$cf_del_keys = grep { /^Bulk-Delete-CustomField/ } keys %ARGS; +my $cf_add_keys; +@$cf_add_keys = grep { /^Bulk-Add-CustomField/ } keys %ARGS; + +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'} ) { + # Add session attachments if any to be processed by ProcessUpdateMessage + $ARGS{'UpdateAttachments'} = $session{'Attachments'} if ( $session{'Attachments'} ); + + while ( my $Ticket = $Tickets->Next ) { + next unless ( $ARGS{ "UpdateTicket" . $Ticket->Id } ); + + #Update the links + $ARGS{'id'} = $Ticket->id; + + my @updateresults = ProcessUpdateMessage( + TicketObj => $Ticket, + ARGSRef => \%ARGS, + ); + + #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 ); + + foreach my $type (qw(MergeInto DependsOn MemberOf RefersTo)) { + $ARGS{ $Ticket->id . "-" . $type } = $ARGS{"Ticket-$type"}; + $ARGS{ $type . "-" . $Ticket->id } = $ARGS{"$type-Ticket"}; + } + @linkresults = + ProcessTicketLinks( TicketObj => $Ticket, ARGSRef => \%ARGS ); + foreach my $type (qw(MergeInto DependsOn MemberOf RefersTo)) { + delete $ARGS{ $type . "-" . $Ticket->id }; + delete $ARGS{ $Ticket->id . "-" . $type }; + } + + my @cfresults; + + foreach my $list ( $cf_add_keys, $cf_del_keys ) { + next unless $list->[0]; + + + my $op; + if ( $list->[0] =~ /Add/ ) { + $op = 'add'; + + } + elsif ( $list->[0] =~ /Del/ ) { + $op = 'del'; + } + else { + $RT::Logger->crit( + "Got an op that was neither add nor delete. can never happen" + . $list->[0] ); + last; + } + + foreach my $key (@$list) { + my ( $cfid, $cf ); + next if $key =~ /CustomField-(\d+)-Category$/; + if ( $key =~ /CustomField-(\d+)-/ ) { + $cfid = $1; + $cf = RT::CustomField->new( $session{'CurrentUser'} ); + $cf->Load($cfid); + } + else {next} + my @values = + ref( $ARGS{$key} ) eq 'ARRAY' + ? @{ $ARGS{$key} } + : ( $ARGS{$key} ); + map { s/(\r\n|\r)/\n/g; } @values; # fix the newlines + # now break the multiline values into multivalues + @values = map { split( /\n/, $_ ) } @values + unless ( $cf->SingleValue ); + + my $current_values = $Ticket->CustomFieldValues($cfid); + + if ( $cf->Type eq 'DateTime' || $cf->Type eq 'Date' ){ + # Clear out empty string submissions to avoid + # Not set changed to Not set + @values = grep length, @values; + } + + foreach my $value (@values) { + + # Convert for timezone. Without converstion, + # HasEntry and DeleteCustomFieldValue fail because + # the value in the DB is converted. + if ( $op eq 'del' + && ($cf->Type eq 'DateTime' || $cf->Type eq 'Date') ){ + my $DateObj = RT::Date->new( $session{'CurrentUser'} ); + $DateObj->Set( Format => 'unknown', + Value => $value ); + $value = $cf->Type eq 'DateTime' ? $DateObj->ISO + : $DateObj->ISO(Time => 0, Seconds => 0); + } + + if ( $op eq 'del' && $current_values->HasEntry($value) ) { + my ( $id, $msg ) = $Ticket->DeleteCustomFieldValue( + Field => $cfid, + Value => $value + ); + push @cfresults, $msg; + } + + elsif ( $op eq 'add' && !$current_values->HasEntry($value) ) { + my ( $id, $msg ) = $Ticket->AddCustomFieldValue( + Field => $cfid, + Value => $value + ); + push @cfresults, $msg; + } + } + } + } + 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 ); + } + + # Cleanup WebUI + delete $session{'Attachments'}; + + $Tickets->RedoSearch(); +} + +my $TxnCFs = RT::CustomFields->new( $session{CurrentUser} ); +$TxnCFs->LimitToLookupType( RT::Transaction->CustomFieldLookupType ); +$TxnCFs->LimitToGlobalOrObjectId( keys %$seen_queues ); + +</%INIT> +<%args> +$Format => undef +$Page => 1 +$Rows => undef +$RowsPerPage => undef +$Order => 'ASC' +$OrderBy => 'id' +$Query => undef +$SavedSearchId => undef +$SavedChartSearchId => undef +</%args> diff --git a/rt/share/html/Search/Elements/ResultsRSSView b/rt/share/html/Search/Elements/ResultsRSSView index d08771124..a453a8603 100644 --- a/rt/share/html/Search/Elements/ResultsRSSView +++ b/rt/share/html/Search/Elements/ResultsRSSView @@ -46,8 +46,6 @@ %# %# END BPS TAGGED BLOCK }}} <%INIT> -use Encode (); - my $old_current_user; if ( $m->request_comp->path =~ RT->Config->Get('WebNoAuthRegex') ) { @@ -67,8 +65,8 @@ if ( $m->request_comp->path =~ RT->Config->Get('WebNoAuthRegex') ) { # Unescape parts $name =~ s/\%([0-9a-z]{2})/chr(hex($1))/gei; - # convert to perl strings - $name = Encode::decode_utf8($name); + # Decode from bytes to characters + $name = Encode::decode( "UTF-8", $name ); my $user = RT::User->new(RT->SystemUser); $user->Load($name); diff --git a/rt/share/html/Search/Results.tsv b/rt/share/html/Search/Results.tsv index 6d8253e78..376db0ed4 100644 --- a/rt/share/html/Search/Results.tsv +++ b/rt/share/html/Search/Results.tsv @@ -71,7 +71,7 @@ my $col_entry = sub { delete $col->{title} if $col->{title} and $col->{title} =~ /^\s*#\s*$/; return { - header => Encode::encode_utf8(loc($col->{title} || $col->{attribute})), + header => loc($col->{title} || $col->{attribute}), map => $m->comp( "/Elements/ColumnMap", Name => $col->{attribute}, @@ -128,7 +128,7 @@ while (my $row = $Tickets->Next) { # remove tabs from all field values, they screw up the tsv $val = '' unless defined $val; $val =~ s/(?:\n|\r)//g; $val =~ s{\t}{ }g; - Encode::encode_utf8($val); + $val; } @$col)."\n"); } } diff --git a/rt/share/html/Search/Results.tsv.orig b/rt/share/html/Search/Results.tsv.orig new file mode 100644 index 000000000..6d8253e78 --- /dev/null +++ b/rt/share/html/Search/Results.tsv.orig @@ -0,0 +1,137 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC +%# <sales@bestpractical.com> +%# +%# (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 }}} +<%ARGS> +$Format => undef +$Query => '' +$OrderBy => 'id' +$Order => 'ASC' +$PreserveNewLines => 0 +</%ARGS> +<%INIT> + +$r->content_type('text/tab-separated-values'); +$r->header_out('Content-Disposition' => 'attachment;filename="Results.tsv"'); + +my $DisplayFormat = $m->comp('/Elements/ScrubHTML', Content => $Format); + +my @Format = $m->comp('/Elements/CollectionAsTable/ParseFormat', Format => $DisplayFormat); + +my @columns; + +my $should_loc = { map { $_ => 1 } qw(Status) }; + +my $col_entry = sub { + my $col = shift; + # in tsv output, "#" is often a comment character but we use it for "id" + delete $col->{title} + if $col->{title} and $col->{title} =~ /^\s*#\s*$/; + return { + header => Encode::encode_utf8(loc($col->{title} || $col->{attribute})), + map => $m->comp( + "/Elements/ColumnMap", + Name => $col->{attribute}, + Attr => 'value' + ), + should_loc => $should_loc->{$col->{attribute}}, + } +}; + +if ($PreserveNewLines) { + my $col = []; + push @columns, $col; + for (@Format) { + if ($_->{title} eq 'NEWLINE') { + $col = []; + push @columns, $col; + } + else { + push @$col, $col_entry->($_); + } + } +} +else { + push @columns, [map { $_->{attribute} + ? $col_entry->($_) + : () } @Format]; +} + +for (@columns) { + $m->out(join("\t", map { $_->{header} } @$_)."\n"); +} + +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 ); +} + +my $ii = 0; +while (my $row = $Tickets->Next) { + for my $col (@columns) { + $m->out(join("\t", map { + my $val = ProcessColumnMapValue($_->{map}, Arguments => [$row, $ii++], Escape => 0); + $val = loc($val) if $_->{should_loc}; + # remove tabs from all field values, they screw up the tsv + $val = '' unless defined $val; + $val =~ s/(?:\n|\r)//g; $val =~ s{\t}{ }g; + Encode::encode_utf8($val); + } @$col)."\n"); + } +} +$m->abort(); + +</%INIT> diff --git a/rt/share/html/Ticket/Create.html b/rt/share/html/Ticket/Create.html index 697db546b..bd60b5c98 100755 --- a/rt/share/html/Ticket/Create.html +++ b/rt/share/html/Ticket/Create.html @@ -105,8 +105,8 @@ % $m->callback( CallbackName => 'AfterOwner', ARGSRef => \%ARGS ); - <& /Ticket/Elements/EditCustomFields, %ARGS, QueueObj => $QueueObj, InTable => 1 &> - <& /Ticket/Elements/EditTransactionCustomFields, %ARGS, QueueObj => $QueueObj, InTable => 1 &> + <& /Ticket/Elements/EditCustomFields, %ARGS, QueueObj => $QueueObj, InTable => 1, KeepValue => 1 &> + <& /Ticket/Elements/EditTransactionCustomFields, %ARGS, QueueObj => $QueueObj, InTable => 1, KeepValue => 1 &> </table> </&> % $m->callback( CallbackName => 'AfterBasics', QueueObj => $QueueObj, ARGSRef => \%ARGS ); diff --git a/rt/share/html/Ticket/Create.html.orig b/rt/share/html/Ticket/Create.html.orig new file mode 100755 index 000000000..697db546b --- /dev/null +++ b/rt/share/html/Ticket/Create.html.orig @@ -0,0 +1,463 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC +%# <sales@bestpractical.com> +%# +%# (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, + onload => "function () { hide('Ticket-Create-details') }" &> +<& /Elements/Tabs &> + +<& /Elements/ListActions, actions => \@results &> + +<form action="<% RT->Config->Get('WebPath') %>/Ticket/Create.html" method="post" enctype="multipart/form-data" name="TicketCreate"> + <input type="hidden" class="hidden" name="id" value="new" /> + +% $m->callback( CallbackName => 'FormStart', QueueObj => $QueueObj, ARGSRef => \%ARGS ); + +% if ($gnupg_widget) { + <& /Elements/GnuPG/SignEncryptWidget:ShowIssues, self => $gnupg_widget &> +% } + +<div id="Ticket-Create-basics"> +<a name="basics"></a> + +<div id="ticket-create-metadata"> + <&| /Widgets/TitleBox, title => loc("Basics"), class=>'ticket-info-basics' &> + <table width="100%" border="0"> + <& /Ticket/Elements/EditBasics, + InTable => 1, + fields => [ + { name => 'Queue', + comp => '/Elements/SelectQueue', + args => { + Name => 'Queue', + Default => $QueueObj->Name, + QueueObj => $QueueObj, + ShowNullOption => 0, + ShowAllQueues => 0, + OnChange => "document.getElementsByName('id')[0].value = 'refresh'; form.submit()", + }, + }, + { name => 'Status', + comp => '/Elements/SelectStatus', + args => { + Name => "Status", + Default => $ARGS{Status} || $QueueObj->Lifecycle->DefaultOnCreate, + DefaultValue => 0, + SkipDeleted => 1, + QueueObj => $QueueObj, + }, + }, + { name => 'Owner', + comp => '/Elements/SelectOwner', + args => { + Name => "Owner", + Default => $ARGS{Owner} || RT->Nobody->Id, + DefaultValue => 0, + QueueObj => $QueueObj, + }, + } + ] + &> + +% $m->callback( CallbackName => 'AfterOwner', ARGSRef => \%ARGS ); + + <& /Ticket/Elements/EditCustomFields, %ARGS, QueueObj => $QueueObj, InTable => 1 &> + <& /Ticket/Elements/EditTransactionCustomFields, %ARGS, QueueObj => $QueueObj, InTable => 1 &> + </table> + </&> +% $m->callback( CallbackName => 'AfterBasics', QueueObj => $QueueObj, ARGSRef => \%ARGS ); +</div> + +<div id="ticket-create-message"> + <&| /Widgets/TitleBox, title => $title, class => 'messagedetails' &> +<table border="0" cellpadding="0" cellspacing="0"> +<tr> +<td class="label"> +<&|/l&>Requestors</&>: +</td> +<td class="value" colspan="5"> +<& /Elements/EmailInput, Name => 'Requestors', Size => undef, Default => exists($ARGS{Requestors}) ? $ARGS{Requestors} : $session{CurrentUser}->EmailAddress &> +% $m->callback( CallbackName => 'AfterRequestors', QueueObj => $QueueObj, ARGSRef => \%ARGS ); +</td> +</tr> +<tr> +<td class="label"> +<&|/l&>Cc</&>: +</td> +<td class="value" colspan="5"><& /Elements/EmailInput, Name => 'Cc', Size => undef, Default => $ARGS{Cc} &></td> +</tr> + +<tr> + <td class="label"> </td> + <td class="comment" colspan="5"> + <i><font size="-2"> + <&|/l&>(Sends a carbon-copy of this update to a comma-delimited list of email addresses. These people <strong>will</strong> receive future updates.)</&> + </font></i> + </td> +</tr> + +<tr> +<td class="label"> +<&|/l&>Admin Cc</&>: +</td> +<td class="value" colspan="5"><& /Elements/EmailInput, Name => 'AdminCc', Size => undef, Default => $ARGS{AdminCc} &></td> +</tr> + +<tr> + <td class="label"> </td> + <td class="comment" colspan="5"> + <i><font size="-2"> + <&|/l&>(Sends a carbon-copy of this update to a comma-delimited list of administrative email addresses. These people <strong>will</strong> receive future updates.)</&> + </font></i> + </td> +</tr> + +<tr> +<td class="label"> +<&|/l&>Subject</&>: +</td> +<td class="value" colspan="5"> +<input type="text" name="Subject" maxsize="200" value="<%$ARGS{Subject} || ''%>" /> +% $m->callback( %ARGS, CallbackName => 'AfterSubject' ); +</td> +</tr> + +% if ( $gnupg_widget ) { +<tr><td> </td><td colspan="5"> +<& /Elements/GnuPG/SignEncryptWidget, self => $gnupg_widget, QueueObj => $QueueObj &> +</td></tr> +% } + +<tr> +<td colspan="6"> +<&|/l&>Describe the issue below</&>:<br /> +% if ( RT->Config->Get('ArticleOnTicketCreate')) { +<& /Articles/Elements/BeforeMessageBox, %ARGS, QueueObj => $QueueObj &> +% } +% $m->callback( %ARGS, QueueObj => $QueueObj, CallbackName => 'BeforeMessageBox' ); +% if (exists $ARGS{Content}) { +<& /Elements/MessageBox, Default => $ARGS{Content}, IncludeSignature => 0 &> +% } else { +<& /Elements/MessageBox, QuoteTransaction => $QuoteTransaction &> +%} +% $m->callback( %ARGS, QueueObj => $QueueObj, CallbackName => 'AfterMessageBox' ); + +<br /> +</td> +</tr> + + <& /Ticket/Elements/AddAttachments, %ARGS, QueueObj => $QueueObj &> + </table> + </&> + <& /Elements/Submit, Label => loc("Create"), id => 'SubmitTicket' &> + </div> +</div> + +<div id="Ticket-Create-details"> +<a name="details"></a> +<table width="100%" border="0"> +<tr> +<td width="50%" valign="top" class="boxcontainer"> + <div class="ticket-info-basics"> + <&| /Widgets/TitleBox, title => loc('The Basics'), + title_class=> 'inverse', + color => "#993333" &> +<table border="0"> +<tr><td class="label"><&|/l&>Priority</&>:</td> +<td><& /Elements/SelectPriority, + Name => "InitialPriority", + Default => $ARGS{InitialPriority} ? $ARGS{InitialPriority} : $QueueObj->InitialPriority, +&></td></tr> +<tr><td class="label"><&|/l&>Final Priority</&>:</td> +<td><& /Elements/SelectPriority, + Name => "FinalPriority", + Default => $ARGS{FinalPriority} ? $ARGS{FinalPriority} : $QueueObj->FinalPriority, +&></td></tr> +<tr><td class="label"><&|/l&>Time Estimated</&>:</td> +<td> +<& /Elements/EditTimeValue, Name => 'TimeEstimated', Default => $ARGS{TimeEstimated} || '', InUnits => $ARGS{'TimeEstimated-TimeUnits'} &> + +</td></tr> +<tr><td class="label"><&|/l&>Time Worked</&>:</td> +<td> +<& /Elements/EditTimeValue, Name => 'TimeWorked', Default => $ARGS{TimeWorked} || '', InUnits => $ARGS{'TimeWorked-TimeUnits'} &> +</td></tr> +<tr> +<td class="label"><&|/l&>Time Left</&>:</td> +<td> +<& /Elements/EditTimeValue, Name => 'TimeLeft', Default => $ARGS{TimeLeft} || '', InUnits => $ARGS{'TimeLeft-TimeUnits'} &> +</td></tr> +</table> +</&> +<br /> +<div class="ticket-info-dates"> +<&|/Widgets/TitleBox, title => loc("Dates"), + title_class=> 'inverse', + color => "#663366" &> + +<table> +<tr><td class="label"><&|/l&>Starts</&>:</td><td><& /Elements/SelectDate, Name => "Starts", Default => $ARGS{Starts} || '' &></td></tr> +<tr><td class="label"><&|/l&>Due</&>:</td><td><& /Elements/SelectDate, Name => "Due", Default => $ARGS{Due} || '' &></td></tr> +</table> +</&> +</div> +</div> +<br /> +</td> + +<td valign="top" class="boxcontainer"> +<div class="ticket-info-links"> +<&| /Widgets/TitleBox, title => loc('Links'), title_class=> 'inverse' &> + +<em><&|/l&>(Enter ticket ids or URLs, separated with spaces)</&></em> +<table border="0"> +<tr><td class="label"><&|/l&>Depends on</&></td><td><input size="10" name="new-DependsOn" value="<% $ARGS{'new-DependsOn'} || '' %>" /></td></tr> +<tr><td class="label"><&|/l&>Depended on by</&></td><td><input size="10" name="DependsOn-new" value="<% $ARGS{'DependsOn-new'} || '' %>" /></td></tr> +<tr><td class="label"><&|/l&>Parents</&></td><td><input size="10" name="new-MemberOf" value="<% $ARGS{'new-MemberOf'} || '' %>" /></td></tr> +<tr><td class="label"><&|/l&>Children</&></td><td><input size="10" name="MemberOf-new" value="<% $ARGS{'MemberOf-new'} || '' %>" /></td></tr> +<tr><td class="label"><&|/l&>Refers to</&></td><td><input size="10" name="new-RefersTo" value="<% $ARGS{'new-RefersTo'} || '' %>" /></td></tr> +<tr><td class="label"><&|/l&>Referred to by</&></td><td><input size="10" name="RefersTo-new" value="<% $ARGS{'RefersTo-new'} || '' %>" /></td></tr> +<tr><td class="label">Customer ID</td><td><input size="10" name="new-Customer" value="<% $ARGS{'new-Customer'} || '' %>" /></td></tr> + +</table> +</&> +</div> +<br /> + +</td> +</tr> +</table> +<& /Elements/Submit, Label => loc("Create") &> +</div> +</form> + +<%INIT> +$m->callback( CallbackName => "Init", ARGSRef => \%ARGS ); +my $Queue = $ARGS{Queue}; +$session{DefaultQueue} = $Queue; + +if ($CloneTicket) { + my $CloneTicketObj = RT::Ticket->new( $session{CurrentUser} ); + $CloneTicketObj->Load($CloneTicket) + or Abort( loc("Ticket could not be loaded") ); + + my $clone = { + Requestors => join( ',', $CloneTicketObj->RequestorAddresses ), + Cc => join( ',', $CloneTicketObj->CcAddresses ), + AdminCc => join( ',', $CloneTicketObj->AdminCcAddresses ), + InitialPriority => $CloneTicketObj->Priority, + }; + + $clone->{$_} = $CloneTicketObj->$_() + for qw/Owner Subject FinalPriority Status/; + # not TimeWorked, TimeEstimated, or TimeLeft + + $clone->{$_} = $CloneTicketObj->$_->AsString + for grep { $CloneTicketObj->$_->Unix } + map { $_ . "Obj" } qw/Starts Started Due Resolved/; + + my $members = $CloneTicketObj->Members; + my ( @members, @members_of, @refers, @refers_by, @depends, @depends_by ); + my $refers = $CloneTicketObj->RefersTo; + my $get_link_value = sub { + my ($link, $type) = @_; + my $uri_method = $type . 'URI'; + my $local_method = 'Local' . $type; + my $uri = $link->$uri_method; + return if $uri->IsLocal and + $uri->Object and + $uri->Object->isa('RT::Ticket') and + $uri->Object->Type eq 'reminder'; + + return $link->$local_method || $uri->URI; + }; + while ( my $refer = $refers->Next ) { + my $refer_value = $get_link_value->($refer, 'Target'); + push @refers, $refer_value if defined $refer_value; + } + $clone->{'new-RefersTo'} = join ' ', @refers; + + my $refers_by = $CloneTicketObj->ReferredToBy; + while ( my $refer_by = $refers_by->Next ) { + my $refer_by_value = $get_link_value->($refer_by, 'Base'); + push @refers_by, $refer_by_value if defined $refer_by_value; + } + $clone->{'RefersTo-new'} = join ' ', @refers_by; + + my $cfs = $CloneTicketObj->QueueObj->TicketCustomFields(); + while ( my $cf = $cfs->Next ) { + next if $cf->FirstAttribute('NoClone'); + my $cf_id = $cf->id; + my $cf_values = $CloneTicketObj->CustomFieldValues( $cf->id ); + my @cf_values; + while ( my $cf_value = $cf_values->Next ) { + push @cf_values, $cf_value->Content; + } + + if ( @cf_values > 1 && $cf->Type eq 'Select' ) { + $clone->{"Object-RT::Ticket--CustomField-$cf_id-Value"} = \@cf_values; + } + else { + $clone->{"Object-RT::Ticket--CustomField-$cf_id-Value"} = join "\n", + @cf_values; + } + } + + # Pass customer links along (even though cloning of parent links + # in general is disabled). + my $customers = $CloneTicketObj->Customers; + my @customers; + while ( my $customer = $customers->Next ) { + my ($custnum) = $customer->Target =~ /cust_main\/(\d+)$/; + push @customers, $custnum if $custnum; + } + $clone->{'new-Customer'} = join(' ', @customers); + + for ( keys %$clone ) { + $ARGS{$_} = $clone->{$_} if not defined $ARGS{$_}; + } + +} + +my @results; + +my $title = loc("Create a new ticket"); + +my $QueueObj = RT::Queue->new($session{'CurrentUser'}); +$QueueObj->Load($Queue) || Abort(loc("Queue could not be loaded.")); + +$m->callback( QueueObj => $QueueObj, title => \$title, results => \@results, ARGSRef => \%ARGS ); + +$QueueObj->Disabled && Abort(loc("Cannot create tickets in a disabled queue.")); + +my $CFs = $QueueObj->TicketCustomFields(); + +my $ValidCFs = $m->comp( + '/Elements/ValidateCustomFields', + CustomFields => $CFs, + ARGSRef => \%ARGS +); + +ProcessAttachments(ARGSRef => \%ARGS); + +my $checks_failure = 0; + +my $gnupg_widget = $m->comp('/Elements/GnuPG/SignEncryptWidget:new', Arguments => \%ARGS ); +$m->comp( '/Elements/GnuPG/SignEncryptWidget:Process', + self => $gnupg_widget, + QueueObj => $QueueObj, +); + + +if ( !exists $ARGS{'AddMoreAttach'} && ($ARGS{'id'}||'') eq 'new' ) { + my $status = $m->comp('/Elements/GnuPG/SignEncryptWidget:Check', + self => $gnupg_widget, + Operation => 'Create', + QueueObj => $QueueObj, + ); + $checks_failure = 1 unless $status; +} + +# check email addresses for RT's +{ + foreach my $field ( qw(Requestors Cc AdminCc) ) { + my $value = $ARGS{ $field }; + next unless defined $value && length $value; + + my @emails = Email::Address->parse( $value ); + foreach my $email ( grep RT::EmailParser->IsRTAddress($_->address), @emails ) { + push @results, loc("[_1] is an address RT receives mail at. Adding it as a '[_2]' would create a mail loop", $email->format, loc($field =~ /^(.*?)s?$/) ); + $checks_failure = 1; + $email = undef; + } + $ARGS{ $field } = join ', ', map $_->format, grep defined, @emails; + } +} + +my $skip_create = 0; +$m->callback( CallbackName => 'BeforeCreate', ARGSRef => \%ARGS, skip_create => \$skip_create, + checks_failure => $checks_failure, results => \@results ); + +$m->comp( '/Articles/Elements/CheckSkipCreate', ARGSRef => \%ARGS, skip_create => \$skip_create, + checks_failure => $checks_failure, results => \@results ); + +if ((!exists $ARGS{'AddMoreAttach'}) and (defined($ARGS{'id'}) and $ARGS{'id'} eq 'new')) { # new ticket? + if ( $ValidCFs && !$checks_failure && !$skip_create ) { +# CREATE THE TICKET. +# For some reason it's done by a Mason component named "Display.html" +# and the call is buried in obscure error-handling stuff. +# This comment exists to make it more visually obvious. +# ************************************************************ + + $m->comp('Display.html', %ARGS); + +# ************************************************************ +# Execution should not continue here. Display.html calls +# Redirect() which does an $m->abort. We only get here if the +# code dies before then, hence "$@". + $RT::Logger->crit("After display call; error is $@"); + $m->abort(); + } + elsif ( !$ValidCFs ) { + # Invalid CFs + while (my $CF = $CFs->Next) { + my $msg = $m->notes('InvalidField-' . $CF->Id) or next; + push @results, $CF->Name . ': ' . $msg; + } + } +} +PageMenu->child( basics => raw_html => q[<a href="#basics" onclick="return switchVisibility('Ticket-Create-basics','Ticket-Create-details');">] . loc('Basics') . q[</a>]); +PageMenu->child( details => raw_html => q[<a href="#details" onclick="return switchVisibility('Ticket-Create-details','Ticket-Create-basics');">] . loc('Details') . q[</a>]); +</%INIT> + +<%ARGS> +$DependsOn => undef +$DependedOnBy => undef +$MemberOf => undef +$QuoteTransaction => undef +$CloneTicket => undef +</%ARGS> diff --git a/rt/share/html/Ticket/Elements/EditTransactionCustomFields b/rt/share/html/Ticket/Elements/EditTransactionCustomFields index a52ecc349..89a2fab89 100644 --- a/rt/share/html/Ticket/Elements/EditTransactionCustomFields +++ b/rt/share/html/Ticket/Elements/EditTransactionCustomFields @@ -63,8 +63,9 @@ </<% $CELL %>> <<% $CELL %>> <& /Elements/EditCustomField, + %ARGS, CustomField => $CF, - NamePrefix => $NamePrefix + NamePrefix => $NamePrefix, &> % if (my $msg = $m->notes('InvalidField-' . $CF->Id)) { <br /> diff --git a/rt/share/html/Ticket/Elements/EditTransactionCustomFields.orig b/rt/share/html/Ticket/Elements/EditTransactionCustomFields.orig new file mode 100644 index 000000000..a52ecc349 --- /dev/null +++ b/rt/share/html/Ticket/Elements/EditTransactionCustomFields.orig @@ -0,0 +1,112 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC +%# <sales@bestpractical.com> +%# +%# (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 }}} +% $m->callback( CallbackName => 'BeforeTransactionCustomFields', TicketObj => $TicketObj, QueueObj => $QueueObj, NamePrefix => $NamePrefix ); +% if ( $WRAP ) { +<<% $WRAP %> class="edit-transaction-custom-fields"> +% } +% if ($CustomFields->Count) { +% while (my $CF = $CustomFields->Next()) { +% $CF->SetContextObject($TicketObj || $QueueObj); +% next unless $CF->CurrentUserHasRight('ModifyCustomField'); +% next unless $CF->UILocation eq $UILocation; +<<% $FIELD %>> +<<% $CELL %> class="label cflabel"> + <span class="name"><% loc($CF->Name) %>:</span><br /> +% if ( $CF->Type ne 'TimeValue' ) { + <span class="type"><% $CF->FriendlyType %></span> +% } +</<% $CELL %>> +<<% $CELL %>> +<& /Elements/EditCustomField, + CustomField => $CF, + NamePrefix => $NamePrefix +&> +% if (my $msg = $m->notes('InvalidField-' . $CF->Id)) { + <br /> + <span class="cfinvalidfield"><% $msg %></span> +% } +</<% $CELL %>> +</<% $FIELD %>> +% } +% } +% if ( $WRAP ) { +</<% $WRAP %>> +% } +% $m->callback( CallbackName => 'AfterTransactionCustomFields', TicketObj => $TicketObj, QueueObj => $QueueObj, NamePrefix => $NamePrefix ); + +<%INIT> +my $CustomFields; + +if ($TicketObj) { + $CustomFields = $TicketObj->TransactionCustomFields(); +} else { + $CustomFields = $QueueObj->TicketTransactionCustomFields(); +} + +$m->callback( CallbackName => 'MassageTransactionCustomFields', CustomFields => $CustomFields ); + +$AsTable ||= $InTable; +my $FIELD = $AsTable ? 'tr' : 'div'; +my $CELL = $AsTable ? 'td' : 'div'; +my $WRAP = ''; +if ( $AsTable ) { + $WRAP = 'table' unless $InTable; +} else { + $WRAP = 'div'; +} + +</%INIT> +<%ARGS> +$NamePrefix => "Object-RT::Transaction--CustomField-" +$TicketObj => undef +$QueueObj => undef +$AsTable => 0 +$InTable => 0 +$UILocation => '' +</%ARGS> + diff --git a/rt/share/html/Ticket/Elements/PreviewScrips b/rt/share/html/Ticket/Elements/PreviewScrips index 3526f31a7..4067c20a3 100755 --- a/rt/share/html/Ticket/Elements/PreviewScrips +++ b/rt/share/html/Ticket/Elements/PreviewScrips @@ -88,7 +88,7 @@ my %squelched = ProcessTransactionSquelching( \%ARGS ); </ul> % } % if (RT->Config->Get('PreviewScripMessages')) { - <textarea cols="80" rows="5"><%$scrip->ActionObj->TemplateObj->MIMEObj->as_string%></textarea> + <textarea cols="80" rows="5"><% Encode::decode( "UTF-8", $scrip->ActionObj->TemplateObj->MIMEObj->as_string ) %></textarea> % } <br /> % } diff --git a/rt/share/html/Ticket/Elements/ShowUpdateStatus b/rt/share/html/Ticket/Elements/ShowUpdateStatus index 21713a43a..43b51b578 100644 --- a/rt/share/html/Ticket/Elements/ShowUpdateStatus +++ b/rt/share/html/Ticket/Elements/ShowUpdateStatus @@ -56,10 +56,10 @@ </div> <%ARGS> $Ticket +$DisplayPath => $session{'CurrentUser'}->Privileged ? 'Ticket' : 'SelfService' </%ARGS> <%INIT> return unless (RT->Config->Get( 'ShowUnreadMessageNotifications', $session{'CurrentUser'})); my $txn = $Ticket->SeenUpTo or return; -my $DisplayPath = $session{'CurrentUser'}->Privileged ? 'Ticket' : 'SelfService'; </%INIT> diff --git a/rt/share/html/Ticket/Graphs/Elements/ShowGraph b/rt/share/html/Ticket/Graphs/Elements/ShowGraph index 1eae4b6ae..e9a5102dc 100644 --- a/rt/share/html/Ticket/Graphs/Elements/ShowGraph +++ b/rt/share/html/Ticket/Graphs/Elements/ShowGraph @@ -46,7 +46,7 @@ %# %# END BPS TAGGED BLOCK }}} <div><img src="<% RT->Config->Get('WebPath') %>/Ticket/Graphs/<% $id %>?<% $m->comp('/Elements/QueryString', %ARGS) %>" usemap="#<% $graph->{'NAME'} || 'test' %>" style="border: none" /> -<% safe_run_child { Encode::decode_utf8( $graph->as_cmapx ) } |n %> +<% safe_run_child { Encode::decode( "UTF-8", $graph->as_cmapx ) } |n %> </div> <& ShowLegends, %ARGS, Ticket => $ticket &> <%ARGS> diff --git a/rt/share/html/Ticket/ModifyAll.html b/rt/share/html/Ticket/ModifyAll.html index 6fb79e4fe..119cae400 100755 --- a/rt/share/html/Ticket/ModifyAll.html +++ b/rt/share/html/Ticket/ModifyAll.html @@ -105,7 +105,7 @@ </td> </tr> - <tr><td colspan="2"><& /Ticket/Elements/EditTransactionCustomFields, %ARGS, TicketObj => $Ticket &></td></tr> + <tr><td colspan="2"><& /Ticket/Elements/EditTransactionCustomFields, %ARGS, TicketObj => $Ticket, KeepValue => 1, &></td></tr> <& /Ticket/Elements/AddAttachments, %ARGS, TicketObj => $Ticket &> diff --git a/rt/share/html/Ticket/Update.html b/rt/share/html/Ticket/Update.html index ae6b70095..37bb134c2 100755 --- a/rt/share/html/Ticket/Update.html +++ b/rt/share/html/Ticket/Update.html @@ -172,7 +172,7 @@ changeStatus(); % $m->callback( %ARGS, CallbackName => 'AfterWorked', Ticket => $TicketObj ); -<& /Ticket/Elements/EditTransactionCustomFields, %ARGS, TicketObj => $TicketObj, AsTable => 1 &> +<& /Ticket/Elements/EditTransactionCustomFields, %ARGS, TicketObj => $TicketObj, AsTable => 1, KeepValue => 1 &> <!--</table>--> </&> diff --git a/rt/share/html/Ticket/Update.html.orig b/rt/share/html/Ticket/Update.html.orig new file mode 100755 index 000000000..ae6b70095 --- /dev/null +++ b/rt/share/html/Ticket/Update.html.orig @@ -0,0 +1,353 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC +%# <sales@bestpractical.com> +%# +%# (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 &> + +% $m->callback(CallbackName => 'BeforeActionList', ARGSRef => \%ARGS, Ticket => $TicketObj); +<& /Elements/ListActions, actions => \@results &> + +<form action="Update.html" name="TicketUpdate" + method="post" enctype="multipart/form-data"> +% $m->callback( CallbackName => 'FormStart', ARGSRef => \%ARGS, Ticket => $TicketObj, CanRespond => $CanRespond, CanComment => $CanComment, ResponseDefault => $ResponseDefault, CommentDefault => $CommentDefault ); +<input type="hidden" class="hidden" name="QuoteTransaction" value="<% $ARGS{QuoteTransaction}||'' %>" /> +<input type="hidden" class="hidden" name="DefaultStatus" value="<% $DefaultStatus ||''%>" /> +<input type="hidden" class="hidden" name="Action" value="<% $ARGS{Action}||'' %>" /> + +<& /Elements/GnuPG/SignEncryptWidget:ShowIssues, self => $gnupg_widget &> + +<div id="ticket-update-metadata"> + <&|/Widgets/TitleBox, title => loc('Ticket and Transaction') &> +<table width="100%" border="0"> +% $m->callback(CallbackName => 'AfterTableOpens', ARGSRef => \%ARGS, Ticket => $TicketObj); + +<& /Ticket/Elements/EditTransactionCustomFields, + %ARGS, + TicketObj => $TicketObj, + UILocation => 'TimeWorked', +&> + +% my $skip; +% $m->callback( %ARGS, CallbackName => 'BeforeUpdateType', skip => \$skip ); +% if (!$skip) { +<input type="hidden" class="hidden" name="id" value="<%$TicketObj->Id%>" /><br /> +% } +<tr><td class="label"><&|/l&>Update Type</&>:</td> +<td><select name="UpdateType" id="UpdateType"> +% if ($CanComment) { +<option value="private" <% ($ARGS{'UpdateType'} && $ARGS{'UpdateType'} eq "private") ? qq[ selected="selected"] : !$ARGS{'UpdateType'}&&$CommentDefault |n %>><&|/l&>Comments (Not sent to requestors)</&></option> +% } +% if ($CanRespond) { +<option value="response" <% ($ARGS{'UpdateType'} && $ARGS{'UpdateType'} eq "response") ? qq[ selected="selected"] : !$ARGS{'UpdateType'}&&$ResponseDefault |n %>><&|/l&>Reply to requestors</&></option> +% } +</select> + +<script type="text/javascript"> + jQuery(function() { + jQuery("#UpdateType").change(function(ev) { + jQuery(".messagebox-container") + .removeClass("action-response action-private") + .addClass("action-"+ev.target.value); + }); + }); + jQuery(function() { + jQuery("input[name=TxnSendMailTo]").change(function(ev) { + jQuery("input[name=TxnSendMailTo][value="+ev.target.value+"]") + .attr("checked",jQuery(ev.target).attr('checked')); + }); + }); +</script> + +% $m->callback( %ARGS, CallbackName => 'AfterUpdateType' ); +</td></tr> + +<script type="text/javascript"> +function changeStatus() { + var Status_select = document.getElementById('Status'); + var x = Status_select.options[Status_select.selectedIndex].value; + var text = document.getElementById('WillResolve_Date'); + var button = document.getElementById('WillResolve_Date_date_button'); + if (x == 'resolved' || x == 'rejected' || x == 'deleted') { + text.disabled = true; + button.style.display = 'none'; + } + else { + text.disabled = false; + button.style.display = 'inline'; + } +} +</script> + +<& /Ticket/Elements/EditBasics, + TicketObj => $TicketObj, + InTable => 1, + fields => [ + { name => 'Status', + comp => '/Elements/SelectStatus', + args => { + Name => 'Status', + DefaultLabel => loc("[_1] (Unchanged)", loc($TicketObj->Status)), + Default => $ARGS{'Status'} || ($TicketObj->Status eq $DefaultStatus ? undef : $DefaultStatus), + TicketObj => $TicketObj, + QueueObj => $TicketObj->QueueObj, + onchange => 'changeStatus()' + }, + }, + { name => 'Resolve this Ticket on', + comp => '/Elements/SelectDate', + args => { + menu_prefix => 'WillResolve', + current => 0, + ShowTime => 0, + }, + }, + { name => 'Owner', + comp => '/Elements/SelectOwner', + args => { + Name => "Owner", + TicketObj => $TicketObj, + QueueObj => $TicketObj->QueueObj, + DefaultLabel => loc("[_1] (Unchanged)", $m->scomp('/Elements/ShowUser', User => $TicketObj->OwnerObj)), + Default => $ARGS{'Owner'} + } + }, + { name => 'Worked', + comp => '/Elements/EditTimeValue', + args => { + Name => 'UpdateTimeWorked', + Default => $ARGS{UpdateTimeWorked}||'', + InUnits => $ARGS{'UpdateTimeWorked-TimeUnits'}||'minutes', + } + }, + ] +&> + +<script type="text/javascript"> +changeStatus(); +</script> + +% $m->callback( %ARGS, CallbackName => 'AfterWorked', Ticket => $TicketObj ); + +<& /Ticket/Elements/EditTransactionCustomFields, %ARGS, TicketObj => $TicketObj, AsTable => 1 &> + + <!--</table>--> + </&> +</div> + +<div id="ticket-update-message"> + <& /Ticket/Elements/ShowSimplifiedRecipients, TicketObj => $TicketObj, %ARGS &> + + <&|/Widgets/TitleBox, title => loc('Message'), class => 'messagedetails' &> + <table width="100%" border="0"> +<& /Ticket/Elements/UpdateCc, %ARGS, TicketObj => $TicketObj &> + +% if ( $gnupg_widget ) { +<tr><td> </td><td> +<& /Elements/GnuPG/SignEncryptWidget, + self => $gnupg_widget, + TicketObj => $TicketObj, +&> +</td></tr> +% } +% $m->callback( %ARGS, CallbackName => 'AfterGnuPG' ); + +<tr><td class="label"><&|/l&>Subject</&>:</td><td> <input type="text" name="UpdateSubject" value="<% $ARGS{UpdateSubject} || $TicketObj->Subject || '' %>" /> +% $m->callback( %ARGS, CallbackName => 'AfterSubject' ); +</td></tr> + +<tr><td class="label" valign="top"><&|/l&>Message</&>:</td> +<td class="messagebox-container action-<% $type %>"> +<& /Articles/Elements/BeforeMessageBox, %ARGS &> +% $m->callback( %ARGS, CallbackName => 'BeforeMessageBox' ); +% if (exists $ARGS{UpdateContent}) { +% # preserve QuoteTransaction so we can use it to set up sane references/in/reply to +% my $temp = $ARGS{'QuoteTransaction'}; +% delete $ARGS{'QuoteTransaction'}; +<& /Elements/MessageBox, Name=>"UpdateContent", Default=>$ARGS{UpdateContent}, IncludeSignature => 0, %ARGS&> +% $ARGS{'QuoteTransaction'} = $temp; +% } else { +% my $IncludeSignature = 1; +% $IncludeSignature = 0 if $Action ne 'Respond' && !RT->Config->Get('MessageBoxIncludeSignatureOnComment'); +<& /Elements/MessageBox, Name=>"UpdateContent", IncludeSignature => $IncludeSignature, %ARGS &> +% } +% $m->callback( %ARGS, CallbackName => 'AfterMessageBox' ); +</td></tr> + + <& /Ticket/Elements/AddAttachments, %ARGS, TicketObj => $TicketObj &> + </table> +</&> + +% $m->callback( %ARGS, CallbackName => 'BeforeSubmit', Ticket => $TicketObj ); + + <& /Elements/Submit, Label => loc('Update Ticket'), Name => 'SubmitTicket', id => 'SubmitTicket' &> + +% $m->callback( %ARGS, CallbackName => 'BeforeScrips', Ticket => $TicketObj ); + +% if ($TicketObj->CurrentUserHasRight('ShowOutgoingEmail')) { + <&|/Widgets/TitleBox, title => loc('Scrips and Recipients'), id => 'previewscrips', rolledup => RT->Config->Get('SimplifiedRecipients', $session{'CurrentUser'}) &> + <& /Ticket/Elements/PreviewScrips, TicketObj => $TicketObj, %ARGS &> + </&> +% } +</div> + +% $m->callback( %ARGS, CallbackName => 'AfterScrips', Ticket => $TicketObj ); + +% if (my $recips = $m->notes("DryRun-Recipients-".$TicketObj->Id)) { +<input type="hidden" name="TxnRecipients" value="<% join ",",sort keys %{$recips} %>" /> +% } + +</form> +<hr class="clear" /> + +% $m->callback( %ARGS, CallbackName => 'AfterForm', Ticket => $TicketObj ); + +<%INIT> +my $CanRespond = 0; +my $CanComment = 0; +my $checks_failure = 0; + +my $TicketObj = LoadTicket($id); + +my @results; + +$m->callback( Ticket => $TicketObj, ARGSRef => \%ARGS, checks_failure => \$checks_failure, results => \@results, CallbackName => 'Initial' ); + +unless($DefaultStatus){ + $DefaultStatus=($ARGS{'Status'} ||$TicketObj->Status()); +} + +my $title = loc("Update ticket #[_1] ([_2])", $TicketObj->id, $TicketObj->Subject||''); + +# Things needed in the template - we'll do the processing here, just +# for the convenience: + +my ($CommentDefault, $ResponseDefault); +if ($Action ne 'Respond') { + $CommentDefault = qq[ selected="selected"]; + $ResponseDefault = ""; +} else { + $CommentDefault = ""; + $ResponseDefault = qq[ selected="selected"]; +} + +my $type = $ARGS{'UpdateType'} ? $ARGS{'UpdateType'} : + lc $ARGS{'Action'} eq 'respond' ? 'response' : + lc $ARGS{'Action'} eq 'comment' ? 'private' : + 'none' ; + + +$CanRespond = 1 if ( $TicketObj->CurrentUserHasRight('ReplyToTicket') or + $TicketObj->CurrentUserHasRight('ModifyTicket') ); + +$CanComment = 1 if ( $TicketObj->CurrentUserHasRight('CommentOnTicket') or + $TicketObj->CurrentUserHasRight('ModifyTicket') ); + + +ProcessAttachments(ARGSRef => \%ARGS); + +my $gnupg_widget = $m->comp('/Elements/GnuPG/SignEncryptWidget:new', Arguments => \%ARGS ); +$m->comp( '/Elements/GnuPG/SignEncryptWidget:Process', + self => $gnupg_widget, + TicketObj => $TicketObj, +); + +if ( $ARGS{'SubmitTicket'} ) { + + my %squelched = ProcessTransactionSquelching( \%ARGS ); + $ARGS{'SquelchMailTo'} = [keys %squelched] if keys %squelched; + + my $CFs = $TicketObj->TransactionCustomFields; + my $ValidCFs = $m->comp( + '/Elements/ValidateCustomFields', + CustomFields => $CFs, + NamePrefix => "Object-RT::Transaction--CustomField-", + ARGSRef => \%ARGS + ); + unless ( $ValidCFs ) { + $checks_failure = 1; + while (my $CF = $CFs->Next) { + my $msg = $m->notes('InvalidField-' . $CF->Id) or next; + push @results, loc($CF->Name) . ': ' . $msg; + } + } + my $status = $m->comp('/Elements/GnuPG/SignEncryptWidget:Check', + self => $gnupg_widget, + TicketObj => $TicketObj, + ); + $checks_failure = 1 unless $status; +} + +# check email addresses for RT's +{ + foreach my $field ( qw(UpdateCc UpdateBcc) ) { + my $value = $ARGS{ $field }; + next unless defined $value && length $value; + + my @emails = Email::Address->parse( $value ); + foreach my $email ( grep RT::EmailParser->IsRTAddress($_->address), @emails ) { + push @results, loc("[_1] is an address RT receives mail at. Adding it as a '[_2]' would create a mail loop", $email->format, loc(substr($field, 6)) ); + $checks_failure = 1; + $email = undef; + } + $ARGS{ $field } = join ', ', map $_->format, grep defined, @emails; + } +} +my $skip_update = 0; +$m->callback( CallbackName => 'BeforeUpdate', ARGSRef => \%ARGS, skip_update => \$skip_update, + checks_failure => $checks_failure, results => \@results, TicketObj => $TicketObj ); + +if ( !$checks_failure && !$skip_update && exists $ARGS{SubmitTicket} ) { + $m->callback( Ticket => $TicketObj, ARGSRef => \%ARGS, CallbackName => 'BeforeDisplay' ); + return $m->comp('Display.html', TicketObj => $TicketObj, %ARGS); +} +</%INIT> + +<%ARGS> +$id => undef +$Action => undef +$DefaultStatus => undef +</%ARGS> diff --git a/rt/share/html/Tools/Offline.html b/rt/share/html/Tools/Offline.html index 507ca17e2..de49e00c8 100644 --- a/rt/share/html/Tools/Offline.html +++ b/rt/share/html/Tools/Offline.html @@ -114,7 +114,6 @@ if ($ARGS{'Parse'} && $ARGS{'Template'}) { $template .= $buffer; } my $encode = RT::I18N::_GuessCharset( $template ); - require Encode; $template = Encode::decode( $encode, $template ); $template =~ s/\r\n/\n/gs; $action->Parse(Content => $template, Queue => $qname, Requestor => $requestoraddress); diff --git a/rt/share/html/Widgets/TitleBoxStart b/rt/share/html/Widgets/TitleBoxStart index f6655edad..4982315fe 100755 --- a/rt/share/html/Widgets/TitleBoxStart +++ b/rt/share/html/Widgets/TitleBoxStart @@ -81,7 +81,7 @@ $hideable = 1 if $rolledup; # my $page = $m->request_comp->path; -my $title_b64 = MIME::Base64::encode_base64(Encode::encode_utf8($title), ''); +my $title_b64 = MIME::Base64::encode_base64(Encode::encode( "UTF-8", $title), ''); my $tid = "TitleBox--$page--" . join '--', ($class, $bodyclass, $title_b64, $id); |