diff options
Diffstat (limited to 'rt/share/html')
91 files changed, 1556 insertions, 826 deletions
diff --git a/rt/share/html/Admin/CustomFields/Objects.html b/rt/share/html/Admin/CustomFields/Objects.html index 20d79b294..06e3739b2 100644 --- a/rt/share/html/Admin/CustomFields/Objects.html +++ b/rt/share/html/Admin/CustomFields/Objects.html @@ -56,94 +56,104 @@ <form action="Objects.html" method="post"> <input type="hidden" class="hidden" name="id" value="<% $id %>" /> -<input type="hidden" class="hidden" name="UpdateObjs" value="1" /> + +% if ( $is_global ) { +<h2><&|/l&>Applies to all objects</&></h2> +<input type="checkbox" name="RemoveCustomField-<% $CF->id %>" value="0" /> +<&|/l&>check this box to remove this Custom Field from all objects and be able to choose specific objects.</&> +% } else { +<h2><&|/l&>Apply globally</&></h2> + +<input type="checkbox" name="AddCustomField-<% $CF->id %>" value="0" /> +<&|/l&>check this box to apply this Custom Field to all objects.</&> <h2><&|/l&>Selected objects</&></h2> -<& /Admin/Elements/PickObjects, Objects => \@AssignedObjs, id => $id, Checked => 1 &> -<h2><&|/l&>Unselected objects</&></h2> -<& /Admin/Elements/PickObjects, Objects => \@UnassignedObjs, id => $id &> +<& /Elements/CollectionList, + OrderBy => 'id', + Order => 'ASC', + %ARGS, + Collection => $applied, + Rows => 0, + Page => 1, + Format => $format, + DisplayFormat => "'__CheckBox.{RemoveCustomField-". $CF->id ."}__',". $format, + AllowSorting => 0, + ShowEmpty => 0, + PassArguments => [ + qw(id Format Rows Page Order OrderBy), + ], +&> -<& /Elements/Submit, CheckAll => 1, ClearAll => 1 &> +<h2><&|/l&>Unselected objects</&></h2> +<& /Elements/CollectionList, + OrderBy => 'id', + Order => 'ASC', + %ARGS, + Collection => $not_applied, + Rows => 50, + Format => $format, + DisplayFormat => "'__CheckBox.{AddCustomField-". $CF->id ."}__',". $format, + AllowSorting => 1, + ShowEmpty => 0, + PassArguments => [ + qw(id Format Rows Page Order OrderBy), + ], +&> + +% } + +<& /Elements/Submit, Name => 'UpdateObjs' &> </form> <%INIT> my $CF = RT::CustomField->new($session{'CurrentUser'}); $CF->Load($id) or Abort(loc("Could not load CustomField [_1]"), $id); -my $LookupType = $CF->LookupType || ''; -$LookupType =~ /^([^-]+)/ || - Abort(loc("Object of type [_1] cannot take custom fields", $LookupType)); - -my $Class = $1; -my $CollectionClass; -if (UNIVERSAL::can($Class.'Collection', 'new') ) { -$CollectionClass = $Class.'Collection'; - -} elsif (UNIVERSAL::can($Class.'es', 'new') ) { - $CollectionClass = $Class.'es'; -} elsif (UNIVERSAL::can($Class.'s', 'new') ) { - $CollectionClass = $Class.'s'; - -} else { - Abort(loc("Can't find a collection class for '[_1]'", $Class)); -} - - -my $title = loc('Modify associated objects for [_1]', $CF->Name); +my $class = $CF->RecordClassFromLookupType; +Abort(loc("Something wrong. Contact system administrator")) + unless $class; -my $Objects = $CollectionClass->new($session{'CurrentUser'}); +my (@results); -# If CF is a Group CF, only display user-defined groups -if ($Class eq 'RT::Group') { - $Objects->LimitToUserDefinedGroups; +if ( $UpdateObjs ) { + if ( defined (my $del = $ARGS{'RemoveCustomField-'.$CF->id}) ) { + foreach my $id ( ref $del? (@$del) : ($del) ) { + my $object = $class->new( $session{'CurrentUser'} ); + if ( $id ) { + $object->Load( $id ); + next unless $object->id; + } + + my ($status, $msg) = $CF->RemoveFromObject( $object ); + push @results, $msg; + } + } + if ( defined (my $add = $ARGS{'AddCustomField-'.$CF->id}) ) { + foreach my $id ( ref $add? (@$add) : ($add) ) { + my $object = $class->new( $session{'CurrentUser'} ); + if ( $id ) { + $object->Load( $id ); + next unless $object->id; + } + + my ($status, $msg) = $CF->AddToObject( $object ); + push @results, $msg; + } + } } -my (@results); -my (@AssignedObjs, @UnassignedObjs); - -$Objects->UnLimit; -$Objects->OrderBy( FIELD => 'Name' ); +my $is_global = $CF->IsApplied(0); +my $applied = $CF->AppliedTo; +my $not_applied = $CF->NotAppliedTo; -my $ObjectCFs; -$ObjectCFs = RT::ObjectCustomFields->new($session{'CurrentUser'}); -$ObjectCFs->UnLimit; -$ObjectCFs->LimitToCustomField($id); +my $collection_class = ref($applied); +$collection_class =~ s/^RT:://; -my %seen; -while (my $OCF = $ObjectCFs->Next) { - $seen{$OCF->ObjectId}++; -} +my $format = RT->Config->Get('AdminSearchResultFormat')->{$collection_class} + || '__id__,__Name__'; -while (my $obj = $Objects->Next) { - my $obj_id = $obj->Id; - - if ($UpdateObjs) { - # Go through and delete all the custom field relationships that this object - # no longer has - my $key = "Object-$obj_id-CF-$id"; - if ($ARGS{$key}) { - if (!$seen{$obj_id}) { - my ($val, $msg) = $CF->AddToObject($obj); - push (@results, $msg); - push @UnassignedObjs, $obj if !$val; - } - } - else { - push @UnassignedObjs, $obj; - if ($seen{$obj_id}) { - my ($val, $msg) = $CF->RemoveFromObject($obj); - push (@results, $msg); - pop @UnassignedObjs if !$val; - } - } - } - elsif (!$seen{$obj_id}) { - push @UnassignedObjs, $obj; - } - next if @UnassignedObjs and $UnassignedObjs[-1] == $obj; - push @AssignedObjs, $obj; -} +my $title = loc('Modify associated objects for [_1]', $CF->Name); </%INIT> <%ARGS> diff --git a/rt/share/html/Admin/CustomFields/index.html b/rt/share/html/Admin/CustomFields/index.html index 139b8ebd6..16fb593f6 100644 --- a/rt/share/html/Admin/CustomFields/index.html +++ b/rt/share/html/Admin/CustomFields/index.html @@ -45,40 +45,38 @@ %# those contributions and any derivatives thereof. %# %# END BPS TAGGED BLOCK }}} -<& /Admin/Elements/Header, Title => loc('Select a Custom Field') &> +<& /Admin/Elements/Header, Title => $title &> <& /Admin/Elements/CustomFieldTabs, current_tab => 'Admin/CustomFields/', - Title => loc('Select a Custom Field') &> + Title => $title, +&> -% my @types; -% my $prev_lookup = ''; -% while (my $CustomFieldObj = $CustomFields->Next) { -% next unless $CustomFieldObj->CurrentUserHasRight('AdminCustomField'); -% my $lookup = $CustomFieldObj->FriendlyLookupType; -% if ($lookup ne $prev_lookup) { -% if ($prev_lookup) { -</ul> -% } -<h2><% loc("Custom Fields for [_1]", $lookup) %></h2> -<ul> -% $prev_lookup = $lookup; -% push @types, [$lookup, $CustomFieldObj->LookupType]; -% } -% -<li> -<a href="Modify.html?id=<% $CustomFieldObj->id %>"><% $CustomFieldObj->Name %>: <% $CustomFieldObj->Description %></a> -</li> -% } -% if ($prev_lookup) { -</ul> +% my $tmp = RT::CustomField->new( $session{'CurrentUser'} ); +% if ( $Type ) { +<h2><% loc("Custom Fields for [_1]", $tmp->FriendlyLookupType( $Type )) %></h2> % } +<& /Elements/CollectionList, + OrderBy => 'LookupType|Name', + Order => 'ASC|ASC', + Rows => 50, + %ARGS, + Collection => $CustomFields, + Format => $Format, + DisplayFormat => ($Type? '' : '__FriendlyLookupType__,'). $Format, + AllowSorting => 1, + PassArguments => [ + qw(Format Rows Page Order OrderBy), + qw(Type ShowDisabled) + ], +&> + <form action="<%RT->Config->Get('WebPath')%>/Admin/CustomFields/index.html" method="get"> <&|/l&>Only show custom fields for:</&> <select name="Type"> <option value="" <% !$Type && 'selected="selected"'%> ><% loc('(any)') %></option> -% for (@types) { -<option value="<% $_->[1] %>" <% $_->[1] eq $Type && 'selected="selected"'%> ><% $_->[0] %></option> +% for my $type ( $tmp->LookupTypes ) { +<option value="<% $type %>" <% $type eq $Type && 'selected="selected"'%> ><% $tmp->FriendlyLookupType( $type ) %></option> % } </select> <br /> @@ -92,8 +90,12 @@ <%args> $Type => '' $ShowDisabled => 0 + +$Format => undef </%args> <%INIT> +my $title = loc('Select a Custom Field'); + $Type ||= $ARGS{'type'} || ''; if ( !$Type && $ARGS{'type'} ) { $Type ||= $ARGS{'type'}; @@ -102,7 +104,9 @@ if ( !$Type && $ARGS{'type'} ) { my $CustomFields = RT::CustomFields->new($session{'CurrentUser'}); $CustomFields->UnLimit; -$CustomFields->{'find_disabled_rows'} = 1 if $ShowDisabled; +$CustomFields->FindAllRows if $ShowDisabled; $CustomFields->LimitToLookupType( $Type ) if $Type; -$CustomFields->OrderByCols( { FIELD => 'LookupType' }, { FIELD => 'Name' } ); + +$Format ||= RT->Config->Get('AdminSearchResultFormat')->{'CustomFields'}; + </%INIT> diff --git a/rt/share/html/Admin/Elements/EditCustomFields b/rt/share/html/Admin/Elements/EditCustomFields index 89c6d0f65..0767e4ae4 100755 --- a/rt/share/html/Admin/Elements/EditCustomFields +++ b/rt/share/html/Admin/Elements/EditCustomFields @@ -51,155 +51,126 @@ <input type="hidden" class="hidden" name="id" value="<% $Object->Id || ''%>" /> <input type="hidden" class="hidden" name="ObjectType" value="<% $ObjectType %>" /> <input type="hidden" class="hidden" name="SubType" value="<% $SubType %>" /> -<input type="hidden" class="hidden" name="UpdateCFs" value="1" /> -% if ($Object->Id) { -<h2><&|/l&>Global Custom Fields</&></h2> -<& PickCustomFields, CustomFields => \@GlobalCFs, ReadOnly => 1, id => $id, SubType => $SubType &> -% } <h2><&|/l&>Selected Custom Fields</&></h2> -<& PickCustomFields, CustomFields => [$ObjectCFs->CustomFields], id => $id, Checked => 1, SubType => $SubType &> -<h2><&|/l&>Unselected Custom Fields</&></h2> -<& PickCustomFields, CustomFields => \@UnassignedCFs, id => $id, SubType => $SubType &> +<& /Elements/CollectionList, + %ARGS, + Collection => $applied_cfs, + Rows => 0, + Page => 1, + Format => $format, + DisplayFormat => + $id + ? ("'__RemoveCheckBox.{$id}__',". $format .", '__MoveCF.{$id}__'") + : ("'__CheckBox.{RemoveCustomField}__',". $format .", '__MoveCF.{$id}__'"), + AllowSorting => 0, + ShowEmpty => 0, + PassArguments => [ + qw(Page Order OrderBy), + qw(id ObjectType SubType), + ], +&> -<& /Elements/Submit, CheckAll => 1, ClearAll => 1 &> +<h2><&|/l&>Unselected Custom Fields</&></h2> +<& /Elements/CollectionList, + OrderBy => 'Name', + Order => 'ASC', + %ARGS, + Collection => $not_applied_cfs, + Rows => 50, + Format => $format, + DisplayFormat => "'__CheckBox.{AddCustomField}__',". $format, + AllowSorting => 1, + ShowEmpty => 0, + PassArguments => [ + qw(Page Order OrderBy), + qw(id ObjectType SubType), + ], +&> + +<& /Elements/Submit, Name => 'UpdateCFs' &> </form> <%INIT> -my $CustomFields = RT::CustomFields->new($session{'CurrentUser'}); -my @results; -my (@GlobalCFs, @UnassignedCFs); - -my $id = $Object->Id; +my $id = $Object->Id || 0; if ($id and !$Object->CurrentUserHasRight('AssignCustomFields')) { $m->out('<p><i>', loc('(No custom fields)'), '</i></p>'); return; } +my @results; + my $lookup = $ObjectType; $lookup .= "-$SubType" if $SubType; -$CustomFields->LimitToLookupType($lookup); -$CustomFields->OrderBy( FIELD => 'Name' ); - - -my ($GlobalCFs, $ObjectCFs); -$ObjectCFs = RT::ObjectCustomFields->new($session{'CurrentUser'}); -$ObjectCFs->UnLimit; -$ObjectCFs->LimitToObjectId($id); -$ObjectCFs->LimitToLookupType($lookup); - -# Check sanity of SortOrders -my %SortOrders; -$SortOrders{ $_->SortOrder }++ - while ($_ = $ObjectCFs->Next); - -# If there are duplicates, run though and squash them -if (grep $_ > 1, values %SortOrders) { - my $i = 1; - while ( my $ObjectCF = $ObjectCFs->Next ) { - $ObjectCF->SetSortOrder( $i++ ); +## deal with moving sortorder of custom fields +if ( $MoveCustomFieldUp ) { { + my $record = RT::ObjectCustomField->new( $session{'CurrentUser'} ); + $record->LoadByCols( ObjectId => $id, CustomField => $MoveCustomFieldUp ); + unless ( $record->id ) { + push @results, loc("Custom field #[_1] is not applied to this object", $MoveCustomFieldUp); + last; } - $ObjectCFs->GotoFirstItem; -} - -# {{{ deal with moving sortorder of custom fields -if ($CustomField and $Move) { - my $SourceObj = RT::ObjectCustomField->new($session{'CurrentUser'}); - $SourceObj->LoadByCols( ObjectId => $id, CustomField => $CustomField ); - - my $TargetObj; - my $target_order = $SourceObj->SortOrder + $Move; - while (my $ObjectCF = $ObjectCFs->Next) { - my $this_order = $ObjectCF->SortOrder; - - # if we have an exact match, finish the loop now - ($TargetObj = $ObjectCF, last) if $this_order == $target_order; - - # otherwise, we need to apropos toward the general direction - # ... first, check the sign is correct - next unless ($this_order - $SourceObj->SortOrder) * $Move > 0; - # ... next, see if we already have a candidate - if ($TargetObj) { - # ... if yes, compare the delta and choose the smaller one - my $orig_delta = abs($TargetObj->SortOrder - $target_order); - my $this_delta = abs($this_order - $target_order); - next if $orig_delta < $this_delta; - } - - $TargetObj = $ObjectCF; + my ($status, $msg) = $record->MoveUp; + push @results, $msg; +} } +if ( $MoveCustomFieldDown ) { { + my $record = RT::ObjectCustomField->new( $session{'CurrentUser'} ); + $record->LoadByCols( ObjectId => $id, CustomField => $MoveCustomFieldDown ); + unless ( $record->id ) { + push @results, loc("Custom field #[_1] is not applied to this object", $MoveCustomFieldDown); + last; } - if ($TargetObj) { - # swap their sort order - my ($s, $t) = ($SourceObj->SortOrder, $TargetObj->SortOrder); - $TargetObj->SetSortOrder($s); - $SourceObj->SetSortOrder($t); - # because order changed, we must redo search for subsequent uses + my ($status, $msg) = $record->MoveDown; + push @results, $msg; +} } + +if ( $UpdateCFs ) { + foreach my $cf_id ( @AddCustomField ) { + my $CF = RT::CustomField->new( $session{'CurrentUser'} ); + $CF->Load( $cf_id ); + unless ( $CF->id ) { + push @results, loc("Couldn't load CustomField #[_1]", $cf_id); + next; + } + my ($status, $msg) = $CF->AddToObject( $Object ); + push @results, $msg; + } + foreach my $cf_id ( @RemoveCustomField ) { + my $CF = RT::CustomField->new( $session{'CurrentUser'} ); + $CF->Load( $cf_id ); + unless ( $CF->id ) { + push @results, loc("Couldn't load CustomField #[_1]", $cf_id); + next; + } + my ($status, $msg) = $CF->RemoveFromObject( $Object ); + push @results, $msg; } - - $ObjectCFs->GotoFirstItem; -} -# }}} - -if ($id) { - $GlobalCFs = RT::ObjectCustomFields->new($session{'CurrentUser'}); - $GlobalCFs->LimitToObjectId(0); - $GlobalCFs->LimitToLookupType($lookup); } -while (my $cf = $CustomFields->Next) { - my $cf_id = $cf->Id; +my $applied_cfs = RT::CustomFields->new( $session{'CurrentUser'} ); +$applied_cfs->LimitToLookupType($lookup); +$applied_cfs->LimitToGlobalOrObjectId($id); +$applied_cfs->ApplySortOrder; - if ($GlobalCFs and $GlobalCFs->HasEntryForCustomField($cf_id)) { - push @GlobalCFs, $cf; - next; - } +my $not_applied_cfs = RT::CustomFields->new( $session{'CurrentUser'} ); +$not_applied_cfs->LimitToLookupType($lookup); +$not_applied_cfs->LimitToNotApplied( $id ? ($id, 0) : (0) ); - if ($UpdateCFs) { - # Go through and delete all the custom field relationships that this object - # no longer has - my $key = "Object-$id-CF-$cf_id"; - if ($ARGS{$key}) { - if (!$ObjectCFs->HasEntryForCustomField($cf_id)) { - my ($val, $msg) = $cf->AddToObject($Object); - push (@results, $msg); - push @UnassignedCFs, $cf if !$val; - } - } - else { - push @UnassignedCFs, $cf; - if ($ObjectCFs->HasEntryForCustomField($cf_id)) { - my ($val, $msg) = $cf->RemoveFromObject($Object); - push (@results, $msg); - pop @UnassignedCFs if !$val; - } - } - } - elsif (!$ObjectCFs->HasEntryForCustomField($cf_id)) { - push @UnassignedCFs, $cf; - } - else { - } -} - -# redo search... -$ObjectCFs = RT::ObjectCustomFields->new($session{'CurrentUser'}); -$ObjectCFs->UnLimit; -$ObjectCFs->LimitToObjectId($id); -$ObjectCFs->LimitToLookupType($lookup); +my $format = RT->Config->Get('AdminSearchResultFormat')->{'CustomFields'}; </%INIT> <%ARGS> -$title => undef -$Move => undef -$Source => undef -$CustomField => undef -$FindDisabledCustomFields => undef -$UpdateCFs => 0 $Object $ObjectType $SubType => '' + +$UpdateCFs => undef +@RemoveCustomField => () +@AddCustomField => () +$MoveCustomFieldUp => undef +$MoveCustomFieldDown => undef </%ARGS> diff --git a/rt/share/html/Admin/Elements/EditScrip b/rt/share/html/Admin/Elements/EditScrip index 29ec71cd7..2bcf64d49 100755 --- a/rt/share/html/Admin/Elements/EditScrip +++ b/rt/share/html/Admin/Elements/EditScrip @@ -56,6 +56,7 @@ <tr><td align="right"><&|/l&>Description</&>:</td><td> <input name="Scrip-<% $id %>-Description" + size="60" value="<% $ARGS{"Scrip-$id-Description"} || $scrip->Description || '' %>" /> </td></tr> diff --git a/rt/share/html/Admin/Elements/EditScrips b/rt/share/html/Admin/Elements/EditScrips index df349e1b9..dce0390fd 100755 --- a/rt/share/html/Admin/Elements/EditScrips +++ b/rt/share/html/Admin/Elements/EditScrips @@ -109,10 +109,7 @@ foreach my $id ( grep $_, @DeleteScrip, map /^DeleteScrip-(\d+)/, keys %ARGS ) { } # }}} -my $dir_path = $m->request_comp->dir_path; -$Format ||= qq{'<a href="__WebPath__$dir_path/Scrip.html?id=__id__&Queue=$id">__id__</a>/TITLE:#'} - .qq{,'<a href="__WebPath__$dir_path/Scrip.html?id=__id__&Queue=$id">__Description__</a>/TITLE:Description'} - .q{,__Stage__, __Condition__, __Action__, __Template__}; +$Format ||= RT->Config->Get('AdminSearchResultFormat')->{'Scrips'}; </%init> diff --git a/rt/share/html/Admin/Elements/EditTemplates b/rt/share/html/Admin/Elements/EditTemplates index 0bd68c2c0..7d7d930ce 100755 --- a/rt/share/html/Admin/Elements/EditTemplates +++ b/rt/share/html/Admin/Elements/EditTemplates @@ -73,10 +73,7 @@ </form> <%INIT> -my $dir_path = $m->request_comp->dir_path; -$Format ||= qq{'<a href="__WebPath__$dir_path/Template.html?Queue=$id&Template=__id__">__id__</a>/TITLE:#'} - .qq{,'<a href="__WebPath__$dir_path/Template.html?Queue=$id&Template=__id__">__Name__</a>/TITLE:Name'} - .qq{,'__Description__'}; +$Format ||= RT->Config->Get('AdminSearchResultFormat')->{'Templates'}; my $QueueObj = RT::Queue->new( $session{'CurrentUser'} ); $QueueObj->Load( $id ) if $id; diff --git a/rt/share/html/Admin/Groups/index.html b/rt/share/html/Admin/Groups/index.html index 078f51bd9..17b760c26 100755 --- a/rt/share/html/Admin/Groups/index.html +++ b/rt/share/html/Admin/Groups/index.html @@ -113,10 +113,7 @@ else { $caption = loc("User-defined groups"); } - -$Format ||= q{'<a href="__WebPath__/Admin/Groups/Modify.html?id=__id__">__id__</a>/TITLE:#'} - .q{,'<a href="__WebPath__/Admin/Groups/Modify.html?id=__id__">__Name__</a>/TITLE:Name'} - .q{,'__Description__'}; +$Format ||= RT->Config->Get('AdminSearchResultFormat')->{'Groups'}; </%INIT> <%ARGS> diff --git a/rt/share/html/Admin/Queues/Modify.html b/rt/share/html/Admin/Queues/Modify.html index df97a68c7..c6ffe179f 100755 --- a/rt/share/html/Admin/Queues/Modify.html +++ b/rt/share/html/Admin/Queues/Modify.html @@ -194,6 +194,13 @@ if ( $QueueObj->Id ) { ); push @results, @linkresults; push @results, ProcessObjectCustomFieldUpdates( ARGSRef => \%ARGS, Object => $QueueObj ); + if ( RT->Config->Get('RTAddressRegexp') ) { + foreach my $address ( $QueueObj->CorrespondAddress, $QueueObj->CommentAddress ) { + next unless defined $address && length $address; + next if RT::EmailParser->IsRTAddress( $address ); + push @results, loc("RTAddressRegexp option in the config doesn't match [_1]", $address ); + } + } } </%INIT> diff --git a/rt/share/html/Admin/Queues/index.html b/rt/share/html/Admin/Queues/index.html index 52e7b3bfd..c0131b14f 100755 --- a/rt/share/html/Admin/Queues/index.html +++ b/rt/share/html/Admin/Queues/index.html @@ -92,7 +92,7 @@ <%INIT> my $queues = new RT::Queues($session{'CurrentUser'}); -$queues->{'find_disabled_rows'} = 1 if $FindDisabledQueues; +$queues->FindAllRows if $FindDisabledQueues; my ($caption); if ( defined $QueueString && length $QueueString ) { @@ -111,9 +111,7 @@ if ( defined $QueueString && length $QueueString ) { : loc("Enabled Queues"); } -$Format ||= q{'<a href="__WebPath__/Admin/Queues/Modify.html?id=__id__">__id__</a>/TITLE:#'} - .q{,'<a href="__WebPath__/Admin/Queues/Modify.html?id=__id__">__Name__</a>/TITLE:Name'} - .q{,__Description__,__Address__,__Priority__,__DefaultDueIn__,__Disabled__}; +$Format ||= RT->Config->Get('AdminSearchResultFormat')->{'Queues'}; </%INIT> <%ARGS> diff --git a/rt/share/html/Admin/Tools/Configuration.html b/rt/share/html/Admin/Tools/Configuration.html index eb48af19c..22c846aca 100644 --- a/rt/share/html/Admin/Tools/Configuration.html +++ b/rt/share/html/Admin/Tools/Configuration.html @@ -50,9 +50,7 @@ require Module::Versions::Report; my $title = loc('System Configuration'); unless ($session{'CurrentUser'}->HasRight( Object=> $RT::System, Right => 'SuperUser')) { Abort(loc('This feature is only available to system administrators')); -} - - +} </%init> <& /Admin/Elements/Header, Title => $title &> <& /Admin/Elements/ToolTabs, @@ -60,18 +58,15 @@ unless ($session{'CurrentUser'}->HasRight( Object=> $RT::System, Right => 'Super current_subtab => 'Admin/Tools/Configuration.html', Title => $title &> - - -<h2><&|/l&>Loaded perl modules</&></h2> -% my $report = Module::Versions::Report::report(); -% my @report = grep /v\d/, split("\n",$report); -<pre> -<% join('<br />', @report) |n %> -</pre> - -<h2><&|/l&>RT Config</&></h2> -<table> +<&|/Widgets/TitleBox, title => loc("RT Configuration") &> +<table border="0" cellspacing="0" cellpadding="5" width="100%" class="collection"> +<tr class="collection-as-table"> +<th class="collection-as-table"><&|/l&>Option</&></th> +<th class="collection-as-table"><&|/l&>Value</&></th> +<th class="collection-as-table"><&|/l&>Source</&></th> +</tr> <%PERL> +my $index_conf; foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) { my $val = RT->Config->Get( $key ); next unless defined $val; @@ -90,9 +85,11 @@ foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) { else { $description = loc("core config"); } + $index_conf++; </%PERL> -<tr><th><% $key %></th> -<td rowspan="2">\ +<tr class="<% $index_conf%2 ? 'oddline' : 'evenline'%>"> +<td class="collection-as-table"><% $key %></td> +<td class="collection-as-table"> % if ( $key =~ /Password(?!Length)/i ) { <em>Password not printed</em>\ % } elsif ( !ref $val ) { @@ -104,19 +101,38 @@ foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) { % } else { <% ref $val %>\ % } -</td></tr> -<tr><td><% $description %></td></tr> +</td> +<td class="collection-as-table" style="white-space: nowrap"> +% if ( $description =~ /^.*site config$/ ) { +<span style="font-weight: bold"><% $description %></span> +% } else { +<% $description %> +% } +</td> +</tr> % } </table> - -<h2><&|/l&>RT Variables</&></h2> -<table> -% { no strict qw/refs/; -% my %config_opt = map { $_ => 1 } RT->Config->Options( Overridable => undef ); -% foreach my $key ( sort keys %{*RT::} ) { -% next if !${'RT::'.$key} || ref ${'RT::'.$key} || $config_opt{ $key }; -<tr><th>RT::<% $key %></th> -<td> +</&> +<table width="100%"> + <tr> + <td valign="top" width="60%" class="boxcontainer"> +<&|/Widgets/TitleBox, title=> loc("RT core variables") &> +<table border="0" cellspacing="0" cellpadding="5" width="100%" class="collection"> +<tr class="collection-as-table"> +<th class="collection-as-table"><&|/l&>Variable</&></th> +<th class="collection-as-table"><&|/l&>Value</&></th> +</tr> +<%PERL> +{ no strict qw/refs/; +my %config_opt = map { $_ => 1 } RT->Config->Options( Overridable => undef ); +my $index_var; +foreach my $key ( sort keys %{*RT::} ) { + next if !${'RT::'.$key} || ref ${'RT::'.$key} || $config_opt{ $key }; + $index_var++; +</%PERL> +<tr class="collection-as-table <% $index_var%2 ? 'oddline' : 'evenline'%>"> +<td class="collection-as-table">RT::<% $key %></td> +<td class="collection-as-table"> % if ( $key =~ /Password(?!Length)/i ) { <em>Password not printed</em> % } else { @@ -127,44 +143,100 @@ foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) { % } % } </table> +</&> -<h2><&|/l&>RT Size</&></h2> -<table> +<&|/Widgets/TitleBox, title => loc("RT Size") &> +<table border="0" cellspacing="0" cellpadding="5" width="100%" class="collection"> +<tr class="collection-as-table"> +<th class="collection-as-table"><&|/l&>Object</&></th> +<th class="collection-as-table"><&|/l&>Size</&></th> +</tr> <%PERL> -for my $type (qw/Ticket Queue Transaction Group/) { - my $class = 'RT::' . $type . 's'; +my ($index_size, $user_count, $privileged_count); +for my $type (qw/Tickets Queues Transactions Groups PrivilegedUsers UnprivilegedUsers/) { + my $count; + my $class = 'RT::' . $type; + $class =~ s/Privileged|Unprivileged//; my $collection = $class->new($RT::SystemUser); $collection->UnLimit; - my $count = $collection->CountAll; + if ($type =~ /PrivilegedUsers/) { + $user_count = $collection->CountAll; + $collection->LimitToPrivileged; + $count = $privileged_count = $collection->CountAll; + } elsif ($type =~ /UnprivilegedUsers/) { + $count = $user_count - $privileged_count; + } else { + $count = $collection->CountAll; + } + $index_size++; </%PERL> -<tr><th><% $type %>s</th> -<td><% $count %></td></tr> +<tr class="<% $index_size%2 ? 'oddline' : 'evenline'%>"> +<td class="collection-as-table"><% $type %></td> +<td class="collection-as-table"><% $count %></td> +</tr> % } +</table> +</&> +</td> +<td valign="top" class="boxcontainer"> -<%PERL> -my $users = RT::Users->new($RT::SystemUser); -$users->UnLimit; -my $user_count = $users->CountAll; +<&|/Widgets/TitleBox, title => loc("Mason template search order") &> +<ol> +% foreach my $path ( map { $_->[1] } $m->interp->comp_root_array ) { +<li><% $path %></li> +% } +</ol> +</&> -$users->LimitToPrivileged; -my $privileged_count = $users->CountAll; -my $unprivileged_count = $user_count - $privileged_count; -</%PERL> -<tr><th>Privileged Users</th> -<td><% $privileged_count %></td></tr> -<tr><th>Unprivileged Users</th> -<td><% $unprivileged_count %></td></tr> +<&|/Widgets/TitleBox, title => loc("Perl library search order") &> +<ol> +% foreach my $inc (@INC) { +<li><% $inc %></li> +% } +</ol> +</&> + +</td> +</table> + +<&|/Widgets/TitleBox, title => loc("Loaded perl modules")&> +<table border="0" cellspacing="0" cellpadding="5" width="100%" class="collection"> +<tr class="collection-as-table"> +<th class="collection-as-table"><&|/l&>Module</&></th> +<th class="collection-as-table"><&|/l&>Version</&></th> +<th class="collection-as-table"><&|/l&>Source</&></th> + + +<%perl> +my $i = 0; +my $report = Module::Versions::Report::report(); +my @report = grep /v\d/, split("\n",$report); +shift @report; # throw away the perl version +my ($ver, $source, $distfile); +foreach my $item (@report) { +if ($item =~ /^\s*(.*?)\s*v(\S+);/) { + $item = $1; + $ver = $2; + $distfile = $item.".pm"; + $distfile =~ s|::|/|g; +} +</%perl> +<tr class="<% $i++ %2 ? 'oddline' : 'evenline'%>"> +<td class="collection-as-table"><% $item %></td> + <td class="collection-as-table"> + <%$ver%> + </td> + <td class="collection-as-table"> + <% $INC{$distfile} %> + </td> +</tr> +% } </table> +</&> -<h2><&|/l&>Perl configuration</&></h2> +<&|/Widgets/TitleBox, title => loc("Perl configuration") &> % require Config; <pre> <% Config::myconfig() %> </pre> - -<h2><&|/l&>Perl Include Paths (@INC)</&></h2> -<pre> -% foreach my $inc (@INC) { -<% $inc %> -% } -</pre> +</&> diff --git a/rt/share/html/Admin/Users/Memberships.html b/rt/share/html/Admin/Users/Memberships.html index ea5dd258b..cd8574d58 100644 --- a/rt/share/html/Admin/Users/Memberships.html +++ b/rt/share/html/Admin/Users/Memberships.html @@ -128,9 +128,7 @@ my $is_not_member = RT::Groups->new( $session{'CurrentUser'} ); $is_not_member->LimitToUserDefinedGroups; $is_not_member->WithoutMember( PrincipalId => $UserObj->Id ); -$Format ||= q{'<a href="__WebPath__/Admin/Groups/Modify.html?id=__id__">__id__</a>/TITLE:#'} - .q{,'<a href="__WebPath__/Admin/Groups/Modify.html?id=__id__">__Name__</a>/TITLE:Name'} - .q{,'__Description__'}; +$Format ||= RT->Config->Get('AdminSearchResultFormat')->{'Groups'}; </%INIT> <%ARGS> $id => undef diff --git a/rt/share/html/Admin/Users/Modify.html b/rt/share/html/Admin/Users/Modify.html index aae38b173..6af7bf378 100755 --- a/rt/share/html/Admin/Users/Modify.html +++ b/rt/share/html/Admin/Users/Modify.html @@ -113,26 +113,11 @@ <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</&><br /> - -% unless (RT->Config->Get('WebExternalAuth') and !RT->Config->Get('WebFallbackToInternalAuth')) { -<table> -<tr> -<td align="right"> -<&|/l&>New Password</&>: -</td> -<td align="left"> -<input type="password" name="Pass1" autocomplete="off" /> -</td> -</tr> -<tr><td align="right"> -<&|/l&>Retype Password</&>: -</td> -<td> -<input type="password" name="Pass2" autocomplete="off" /> -</td> -</tr> -</table> -% } + +<& /Elements/EditPassword, + User => $UserObj, + Name => [qw(CurrentPass Pass1 Pass2)], +&> </&> % $m->callback( %ARGS, CallbackName => 'LeftColumnBottom', UserObj => $UserObj ); </td> @@ -364,22 +349,20 @@ if ($UserObj->Id && $id ne 'new') { # }}} } + +my %password_cond = $UserObj->CurrentUserRequireToSetPassword; if ( $UserObj->Id ) { - my $password_not_set; # Deal with Password field - if ( !$Pass1 and !$Pass2 ) { - $password_not_set = 1; - } elsif ( $Pass1 ne $Pass2 ) { - $password_not_set = 1; - push @results, loc("Passwords do not match."); - } elsif ( $Pass1 eq $Pass2 and !$UserObj->IsPassword($Pass1) ) { - my ($code, $msg) = $UserObj->SetPassword($Pass1); - push @results, loc_fuzzy($msg); - $password_not_set = 1 unless $code; + 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."); } - if ($id eq 'new' and $password_not_set) { - push @results, loc("A password was not set, so user won't be able to login."); - } } @@ -431,7 +414,8 @@ $City => undef $State => undef $Zip => undef $Country => undef +$CurrentPass => undef $Pass1 => undef -$Pass2=> undef +$Pass2 => undef $Create=> undef </%ARGS> diff --git a/rt/share/html/Admin/Users/index.html b/rt/share/html/Admin/Users/index.html index e9a58183d..88a775fc3 100755 --- a/rt/share/html/Admin/Users/index.html +++ b/rt/share/html/Admin/Users/index.html @@ -93,7 +93,7 @@ <%INIT> my $caption; my $users = RT::Users->new( $session{'CurrentUser'} ); -$users->{'find_disabled_rows'} = 1 if $FindDisabledUsers; +$users->FindAllRows if $FindDisabledUsers; if ( defined($UserString) && length $UserString ) { $caption = loc("Users matching search criteria"); @@ -117,9 +117,7 @@ else { $users->LimitToPrivileged; } -$Format ||= q{'<a href="__WebPath__/Admin/Users/Modify.html?id=__id__">__id__</a>/TITLE:#'} - .q{,'<a href="__WebPath__/Admin/Users/Modify.html?id=__id__">__Name__</a>/TITLE:Name'} - .q{,__RealName__, __EmailAddress__}; +$Format ||= RT->Config->Get('AdminSearchResultFormat')->{'Users'}; </%INIT> <%ARGS> diff --git a/rt/share/html/Dashboards/Elements/HiddenSearches b/rt/share/html/Dashboards/Elements/HiddenSearches index aa3a67ebb..753d2fe49 100644 --- a/rt/share/html/Dashboards/Elements/HiddenSearches +++ b/rt/share/html/Dashboards/Elements/HiddenSearches @@ -50,6 +50,9 @@ $Dashboard </%args> <%init> +# eliminate deleted searches (id=0) because they confuse this logic +@searches = grep { $_->Id } @searches; + return if @searches == 0; my @display; diff --git a/rt/share/html/Dashboards/Render.html b/rt/share/html/Dashboards/Render.html index 1893b533f..ba01a9d2e 100644 --- a/rt/share/html/Dashboards/Render.html +++ b/rt/share/html/Dashboards/Render.html @@ -110,10 +110,11 @@ for my $sub ($session{'CurrentUser'}->UserObj->Attributes->Named('Subscription') last; } -# otherwise honor their search preferences.. otherwise 20 rows -if (!$rows) { +# otherwise honor their search preferences.. otherwise 50 rows +# $rows == 0 means unlimited, which we don't want to ignore from above +unless (defined($rows)) { my $prefs = $session{'CurrentUser'}->UserObj->Preferences("SearchDisplay") || {}; - $rows = defined($prefs->{'RowsPerPage'}) ? $prefs->{'RowsPerPage'} : 20; + $rows = defined($prefs->{'RowsPerPage'}) ? $prefs->{'RowsPerPage'} : 50; } my $title = loc 'Dashboard [_1]', $DashboardObj->Name; diff --git a/rt/share/html/Download/CustomFieldValue/dhandler b/rt/share/html/Download/CustomFieldValue/dhandler index 218de33c8..d8c703904 100644 --- a/rt/share/html/Download/CustomFieldValue/dhandler +++ b/rt/share/html/Download/CustomFieldValue/dhandler @@ -63,7 +63,10 @@ unless ($OCFV->id) { my $content_type = $OCFV->ContentType || 'text/plain'; -unless (RT->Config->Get('TrustHTMLAttachments')) { +if (RT->Config->Get('AlwaysDownloadAttachments')) { + $r->headers_out->{'Content-Disposition'} = "attachment; filename=" . $OCFV->Content; +} +elsif (!RT->Config->Get('TrustHTMLAttachments')) { $content_type = 'text/plain' if ($content_type =~ /^text\/html/i); } diff --git a/rt/share/html/Elements/CollectionAsTable/Row b/rt/share/html/Elements/CollectionAsTable/Row index fa7474b6c..a1af9f383 100644 --- a/rt/share/html/Elements/CollectionAsTable/Row +++ b/rt/share/html/Elements/CollectionAsTable/Row @@ -54,9 +54,10 @@ $Depth => undef $Warning => undef $ColumnMap => {} $Class => 'RT__Ticket' +$Classes => '' </%ARGS> <%init> -$m->out( '<tr class="' +$m->out( '<tr class="' . $Classes . ' ' . ( $Warning ? 'warnline' : $i % 2 ? 'oddline' : 'evenline' ) . '" >' . "\n" ); use HTML::Entities; diff --git a/rt/share/html/Elements/CollectionList b/rt/share/html/Elements/CollectionList index 6f21420f5..c7bdfd903 100644 --- a/rt/share/html/Elements/CollectionList +++ b/rt/share/html/Elements/CollectionList @@ -54,7 +54,9 @@ if (!$Collection && $Class eq 'RT::Tickets') { my $TotalFound = $Collection->CountAll(); return '' if !$TotalFound && !$ShowEmpty; -if ( @OrderBy ) { +# XXX: ->{'order_by'} is hacky, but there is no way to check if +# collection is ordered or not +if ( @OrderBy && ($AllowSorting || !$Collection->{'order_by'}) ) { if ( $OrderBy[0] =~ /\|/ ) { @OrderBy = split /\|/, $OrderBy[0]; @Order = split /\|/,$Order[0]; @@ -122,13 +124,27 @@ my ($i, $column_map) = (0, {}); while ( my $record = $Collection->Next ) { # Every ten rows, flush the buffer and put something on the page. $m->flush_buffer unless ++$i % 10; + + my $warning = 0; + my $Classes = ''; + + $m->callback( + CallbackName => 'EachRow', + Record => $record, + Warning => \$warning, + Classes => \$Classes, + Format => \@Format, + ); + $m->comp('/Elements/CollectionAsTable/Row', - i => $i, - Format => \@Format, - record => $record, - maxitems => $maxitems, + i => $i, + Format => \@Format, + record => $record, + maxitems => $maxitems, ColumnMap => $column_map, Class => $Class, + Warning => $warning, + Classes => $Classes, ); } diff --git a/rt/share/html/Elements/ColumnMap b/rt/share/html/Elements/ColumnMap index 71517e063..a1475a99d 100644 --- a/rt/share/html/Elements/ColumnMap +++ b/rt/share/html/Elements/ColumnMap @@ -92,6 +92,26 @@ my $COLUMN_MAP = { value => sub { return $_[0]->LastUpdatedByObj->Name } }, + CustomField => { + attribute => sub { return shift @_ }, + title => sub { return pop @_ }, + value => sub { + # Display custom field contents, separated by newlines. + # For Image custom fields we also show a thumbnail here. + + my $values = $_[0]->CustomFieldValues( $_[-1] ); + my @values = map { + ( + ($_->CustomFieldObj->Type eq 'Image') + ? \($m->scomp( '/Elements/ShowCustomFieldImage', Object => $_ )) + : $_->Content + ), + \'<br />', + } @{ $values->ItemsArrayRef }; + pop @values; # Remove that last <br /> + return @values; + }, + }, CheckBox => { title => sub { @@ -136,8 +156,12 @@ my $COLUMN_MAP = { $_ => { value => sub { return \$value } }; } qw(WebPath WebBaseURL WebURL)), + WebRequestPath => { value => sub { substr( $m->request_path, 1 ) } }, + WebRequestPathDir => { value => sub { substr( $m->request_comp->dir_path, 1 ) } }, }; +$COLUMN_MAP->{'CF'} = $COLUMN_MAP->{'CustomField'}; + </%ONCE> <%INIT> $m->callback( COLUMN_MAP => $COLUMN_MAP, CallbackName => 'Once', CallbackOnce => 1 ); diff --git a/rt/share/html/Elements/CreateTicket b/rt/share/html/Elements/CreateTicket index 9c8f3aadf..fd2ba9e53 100755 --- a/rt/share/html/Elements/CreateTicket +++ b/rt/share/html/Elements/CreateTicket @@ -45,6 +45,9 @@ %# those contributions and any derivatives thereof. %# %# END BPS TAGGED BLOCK }}} -<form action="<% RT->Config->Get('WebPath') %>/Ticket/Create.html" name="CreateTicketInQueue" id="CreateTicketInQueue"> -<&|/l, $m->scomp('/Elements/SelectNewTicketQueue', OnChange => 'document.CreateTicketInQueue.submit()')&><input type="submit" class="button" value="New ticket in" /> [_1]</&> +<form action="<% RT->Config->Get('WebPath') %><% $SendTo %>" name="CreateTicketInQueue" id="CreateTicketInQueue"> +<&|/l, $m->scomp('/Elements/SelectNewTicketQueue', OnChange => 'document.CreateTicketInQueue.submit()', SendTo => $SendTo ) &><input type="submit" class="button" value="New ticket in" /> [_1]</&> </form> +<%ARGS> +$SendTo => '/Ticket/Create.html', +</%ARGS> diff --git a/rt/share/html/Elements/EditCustomFieldSelect b/rt/share/html/Elements/EditCustomFieldSelect index 8fe79f9f9..30b06dbd1 100644 --- a/rt/share/html/Elements/EditCustomFieldSelect +++ b/rt/share/html/Elements/EditCustomFieldSelect @@ -52,7 +52,7 @@ % my @category; % my $id = $NamePrefix . $CustomField->Id; % my $out = $m->scomp('SELF:options', %ARGS, SelectedRef => \$selected, CategoryRef => \@category); -% if (@category and not $CustomField->BasedOnObj->id) { +% if (!$HideCategory and @category and not $CustomField->BasedOnObj->id) { <script type="text/javascript" src="<%RT->Config->Get('WebPath')%>/NoAuth/js/cascaded.js"></script> %# XXX - Hide this select from w3m? <select onchange="filter_cascade('<% $id %>-Values', this.value)" name="<% $id %>-Category" class="CF-<%$CustomField->id%>-Edit"> @@ -108,6 +108,7 @@ $Default => undef $Values => undef $Multiple => 0 $Rows => undef +$HideCategory => 0 </%ARGS> <%METHOD options> diff --git a/rt/share/html/Elements/EditLinks b/rt/share/html/Elements/EditLinks index 637762e1b..90acb4692 100755 --- a/rt/share/html/Elements/EditLinks +++ b/rt/share/html/Elements/EditLinks @@ -52,7 +52,7 @@ <table> <tr> - <td class="labeltop"><&|/l&>Depends on</&>:</td> + <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Depends on'), Relation => 'DependsOn' &>:</td> <td class="value"> % while (my $link = $Object->DependsOn->Next) { <input type="checkbox" class="checkbox" name="DeleteLink--<%$link->Type%>-<%$link->Target%>" value="1" /> @@ -61,7 +61,7 @@ </td> </tr> <tr> - <td class="labeltop"><&|/l&>Depended on by</&>:</td> + <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Depended on by'), Relation => 'DependedOnBy' &>:</td> <td class="value"> % while (my $link = $Object->DependedOnBy->Next) { <input type="checkbox" class="checkbox" name="DeleteLink-<%$link->Base%>-<%$link->Type%>-" value="1" /> @@ -70,7 +70,7 @@ </td> </tr> <tr> - <td class="labeltop"><&|/l&>Parents</&>:</td> + <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Parents'), Relation => 'Parents' &>:</td> <td class="value"> % while (my $link = $Object->MemberOf->Next) { <input type="checkbox" class="checkbox" name="DeleteLink--<%$link->Type%>-<%$link->Target%>" value="1" /> @@ -79,7 +79,7 @@ </td> </tr> <tr> - <td class="labeltop"><&|/l&>Children</&>:</td> + <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Children'), Relation => 'Children' &>:</td> <td class="value"> % while (my $link = $Object->Members->Next) { <input type="checkbox" class="checkbox" name="DeleteLink-<%$link->Base%>-<%$link->Type%>-" value="1" /> @@ -88,7 +88,7 @@ </td> </tr> <tr> - <td class="labeltop"><&|/l&>Refers to</&>:</td> + <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Refers to'), Relation => 'RefersTo' &>:</td> <td class="value"> % while (my $link = $Object->RefersTo->Next) { <input type="checkbox" class="checkbox" name="DeleteLink--<%$link->Type%>-<%$link->Target%>" value="1" /> @@ -97,7 +97,7 @@ </td> </tr> <tr> - <td class="labeltop"><&|/l&>Referred to by</&>:</td> + <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Referred to by'), Relation => 'ReferredToBy' &>:</td> <td class="value"> % while (my $link = $Object->ReferredToBy->Next) { % # Skip reminders @@ -134,27 +134,27 @@ </tr> % } <tr> - <td class="label"><&|/l&>Depends on</&>:</td> + <td class="label"><& ShowRelationLabel, id => $id, Label => loc('Depends on'), Relation => 'DependsOn' &>:</td> <td class="entry"><input name="<%$id%>-DependsOn" /></td> </tr> <tr> - <td class="label"><&|/l&>Depended on by</&>:</td> + <td class="label"><& ShowRelationLabel, id => $id, Label => loc('Depended on by'), Relation => 'DependedOnBy' &>:</td> <td class="entry"><input name="DependsOn-<%$id%>" /></td> </tr> <tr> - <td class="label"><&|/l&>Parents</&>:</td> + <td class="label"><& ShowRelationLabel, id => $id, Label => loc('Parents'), Relation => 'Parents' &>:</td> <td class="entry"><input name="<%$id%>-MemberOf" /></td> </tr> <tr> - <td class="label"><&|/l&>Children</&>:</td> + <td class="label"><& ShowRelationLabel, id => $id, Label => loc('Children'), Relation => 'Children' &>:</td> <td class="entry"> <input name="MemberOf-<%$id%>" /></td> </tr> <tr> - <td class="label"><&|/l&>Refers to</&>:</td> + <td class="label"><& ShowRelationLabel, id => $id, Label => loc('Refers to'), Relation => 'RefersTo' &>:</td> <td class="entry"><input name="<%$id%>-RefersTo" /></td> </tr> <tr> - <td class="label"><&|/l&>Referred to by</&>:</td> + <td class="label"><& ShowRelationLabel, id => $id, Label => loc('Referred to by'), Relation => 'ReferredToBy' &>:</td> <td class="entry"> <input name="RefersTo-<%$id%>" /></td> </tr> % $m->callback( CallbackName => 'NewLink' ); diff --git a/rt/share/html/Elements/EditPassword b/rt/share/html/Elements/EditPassword new file mode 100644 index 000000000..3b0ec0b32 --- /dev/null +++ b/rt/share/html/Elements/EditPassword @@ -0,0 +1,34 @@ +% unless ( $cond{'CanSet'} ) { +<% $cond{'Reason'} %><br /> +% } else { +<table> + +% if ( $cond{'RequireCurrent'} ) { +<tr> +<td><&|/l&>Your current password</&>:</td> +<td><input type="password" name="<% $Name[0] %>" size="16" autocomplete="off" /></td> +</tr> +% } + +<tr> +<td><&|/l&>New password</&>:</td> +<td><input type="password" name="<% $Name[1] %>" size="16" autocomplete="off" /></td> +</tr> + +<tr> +<td><&|/l&>Retype Password</&>:</td> +<td><input type="password" name="<% $Name[2] %>" size="16" autocomplete="off" /></td> +</tr> + +</table> +% } + +<%ARGS> +$User +@Name => qw(CurrentPass NewPass1 NewPass2) +</%ARGS> +<%INIT> + +my %cond = $User->CurrentUserRequireToSetPassword; + +</%INIT> diff --git a/rt/share/html/Elements/HeaderJavascript b/rt/share/html/Elements/HeaderJavascript index 6ee88a13b..c4eb17504 100644 --- a/rt/share/html/Elements/HeaderJavascript +++ b/rt/share/html/Elements/HeaderJavascript @@ -111,7 +111,7 @@ $onload => undef typeField.setAttribute('value', 'text/html'); textArea.parentNode.appendChild(typeField); - var oFCKeditor = new FCKeditor( textArea.name, '100%', <% RT->Config->Get('MessageBoxRichTextHeight') %> ); + var oFCKeditor = new FCKeditor( textArea.name, '100%', <% RT->Config->Get('MessageBoxRichTextHeight', $session{CurrentUser} ) %> ); oFCKeditor.BasePath = "<%RT->Config->Get('WebPath')%>/NoAuth/RichText/"; oFCKeditor.ReplaceTextarea(); } diff --git a/rt/share/html/Elements/Login b/rt/share/html/Elements/Login index 8dfbe51d1..e768b0e7a 100755 --- a/rt/share/html/Elements/Login +++ b/rt/share/html/Elements/Login @@ -64,6 +64,21 @@ my $form_action = defined $goto ? $goto : defined $req_uri ? $req_uri : RT->Config->Get('WebPath') ; + +# sanitize $form_action +my $uri = URI->new($form_action); + +# You get undef scheme with a relative uri like "/Search/Build.html" +unless (!defined($uri->scheme) || $uri->scheme eq 'http' || $uri->scheme eq 'https') { + $form_action = RT->Config->Get('WebPath'); +} + +# Make sure we're logging in to the same domain +# You can get an undef authority with a relative uri like "index.html" +my $uri_base_url = URI->new(RT->Config->Get('WebBaseURL')); +unless (!defined($uri->authority) || $uri->authority eq $uri_base_url->authority) { + $form_action = RT->Config->Get('WebPath'); +} </%INIT> % $m->callback( %ARGS, CallbackName => 'Header' ); diff --git a/rt/share/html/Elements/Logo b/rt/share/html/Elements/Logo index 359738b5e..e6cb1ad4b 100644 --- a/rt/share/html/Elements/Logo +++ b/rt/share/html/Elements/Logo @@ -46,10 +46,11 @@ %# %# END BPS TAGGED BLOCK }}} <div id="logo"> -<a href="http://bestpractical.com"><img +<a href="<%$ARGS{'LogoLinkURL'}||RT->Config->Get('LogoLinkURL')%>"><img src="<%$ARGS{'LogoURL'}||RT->Config->Get('LogoURL')%>" - alt="<% loc("Best Practical Solutions, LLC corporate logo") %>" - width="177" height="33" /></a> + alt="<%loc($ARGS{'LogoAltText'}||RT->Config->Get('LogoAltText'))%>" + width="<%$ARGS{'LogoImageWidth'}||RT->Config->Get('LogoImageWidth')%>" + height="<%$ARGS{'LogoImageHeight'}||RT->Config->Get('LogoImageHeight')%>" /></a> % if ( $ShowName ) { <span class="rtname"><% $Name || loc("RT for [_1]", RT->Config->Get('rtname')) %></span> % } diff --git a/rt/share/html/Elements/MessageBox b/rt/share/html/Elements/MessageBox index 4985b23e3..854528c23 100755 --- a/rt/share/html/Elements/MessageBox +++ b/rt/share/html/Elements/MessageBox @@ -46,7 +46,7 @@ %# %# END BPS TAGGED BLOCK }}} <textarea class="messagebox" cols="<% $Width %>" rows="<% $Height %>" <% $wrap_type |n %> name="<% $Name %>" id="<% $Name %>">\ -% $m->callback( %ARGS ); +% $m->callback( %ARGS, SignatureRef => \$signature ); <% $Default || '' %><% $message %><% $signature %></textarea> % $m->callback( %ARGS, CallbackName => 'AfterTextArea' ); <%INIT> diff --git a/rt/share/html/Elements/MyReminders b/rt/share/html/Elements/MyReminders index 25fdf5d48..53e3f99c7 100755 --- a/rt/share/html/Elements/MyReminders +++ b/rt/share/html/Elements/MyReminders @@ -47,6 +47,7 @@ %# END BPS TAGGED BLOCK }}} %# DEPRECATED <&|/Widgets/TitleBox, + class => 'reminders', title => loc("Reminders") &> <table width="100%"> % my $i =0; diff --git a/rt/share/html/Elements/RT__CustomField/ColumnMap b/rt/share/html/Elements/RT__CustomField/ColumnMap new file mode 100644 index 000000000..6d8d76a4c --- /dev/null +++ b/rt/share/html/Elements/RT__CustomField/ColumnMap @@ -0,0 +1,178 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@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> +$Name => undef +$Attr => undef +</%ARGS> +<%ONCE> +my $COLUMN_MAP = { + id => { + title => '#', # loc + attribute => 'id', + align => 'right', + value => sub { return $_[0]->id }, + }, + Disabled => { + title => \' ', + attribute => 'Disabled', + value => sub { return $_[0]->Disabled? $_[0]->loc('Disabled'): $_[0]->loc('Enabled') }, + }, + + map( + { my $c = $_; $c => { + title => $c, attribute => $c, + value => sub { return $_[0]->$c() }, + } } + qw(Name Description Type LookupType Pattern) + ), + map( + { my $c = $_; my $short = $c; $short =~ s/^Friendly//; + $c => { + title => $short, attribute => $short, + value => sub { return $_[0]->$c() }, + } } + qw(FriendlyLookupType FriendlyType FriendlyPattern) + ), + MaxValues => { + title => 'MaxValues', # loc + attribute => 'MaxValues', + value => sub { + my $v = $_[0]->MaxValues; + return !$v ? $_[0]->loc('unlimited') : $v == 0 ? $_[0]->loc('one') : $v; + }, + }, + AppliedTo => { + title => 'Applied', # loc + value => sub { + if ( $_[0]->IsApplied ) { + return $_[0]->loc('Global'); + } + + my $collection = $_[0]->AppliedTo; + return '' unless $collection; + + $collection->RowsPerPage(10); + + my $found = 0; + my $res = ''; + while ( my $record = $collection->Next ) { + $res .= ', ' if $res; + + my $id = ''; + $id = $record->Name if $record->can('Name'); + $id ||= "#". $record->id; + $res .= $id; + + $found++; + } + $res .= ', ...' if $found >= 10; + return $res; + }, + + }, + RemoveCheckBox => { + title => sub { + my $name = 'RemoveCustomField'; + my $checked = $m->request_args->{ $name .'All' }? 'checked="checked"': ''; + + return \qq{<input type="checkbox" name="${name}All" value="1" $checked + onclick="setCheckbox(this.form, '$name', this.checked)" />}; + }, + value => sub { + my $id = $_[0]->id; + return '' if $_[0]->IsApplied; + + my $name = 'RemoveCustomField'; + my $arg = $m->request_args->{ $name }; + + my $checked = ''; + if ( $arg && ref $arg ) { + $checked = 'checked="checked"' if grep $_ == $id, @$arg; + } + elsif ( $arg ) { + $checked = 'checked="checked"' if $arg == $id; + } + return \qq{<input type="checkbox" name="$name" value="$id" $checked />} + }, + }, + MoveCF => { + title => 'Move', + value => sub { + my $id = $_[0]->id; + + my $context = $_[2] || 0; + return '' unless $_[0]->IsApplied( $context ); + + my $name = 'MoveCustomField'; + my $args = $m->caller_args( 1 ); + my @pass = ref $args->{'PassArguments'} + ? @{$args->{'PassArguments'}} + : ($args->{'PassArguments'}); + my %pass = map { $_ => $args->{$_} } grep exists $args->{$_}, @pass; + + my $uri = RT->Config->Get('WebPath') . $m->request_path; + + my @res = ( + \'<a href="', + $uri .'?'. $m->comp("/Elements/QueryString", %pass, MoveCustomFieldUp => $id ), + \'">', loc('[Up]'), \'</a>', + \' <a href="', + $uri .'?'. $m->comp("/Elements/QueryString", %pass, MoveCustomFieldDown => $id ), + \'">', loc('[Down]'), \'</a>' + ); + + return @res; + }, + }, +}; + +</%ONCE> +<%INIT> +$m->callback( COLUMN_MAP => $COLUMN_MAP, CallbackName => 'ColumnMap', CallbackOnce => 1 ); +return GetColumnMapEntry( Map => $COLUMN_MAP, Name => $Name, Attribute => $Attr ); +</%INIT> diff --git a/rt/share/html/Elements/RT__Queue/ColumnMap b/rt/share/html/Elements/RT__Queue/ColumnMap index 5c56004d1..f44ab32c3 100644 --- a/rt/share/html/Elements/RT__Queue/ColumnMap +++ b/rt/share/html/Elements/RT__Queue/ColumnMap @@ -70,43 +70,33 @@ my $COLUMN_MAP = { title => 'Address', # loc value => sub { return ($_[0]->CorrespondAddress||'-') .'/'. ($_[0]->CommentAddress||'-') }, }, - Name => { - title => 'Name', # loc - attribute => 'Name', - value => sub { return $_[0]->Name() }, - }, - Description => { - title => 'Description', # loc - attribute => 'Description', - value => sub { return $_[0]->Description() }, - }, - CorrespondAddress => { - title => 'CorrespondAddress', # loc - attribute => 'CorrespondAddress', - value => sub { return $_[0]->CorrespondAddress() }, - }, - CommentAddress => { - title => 'CommentAddress', # loc - attribute => 'CommentAddress', - value => sub { return $_[0]->CommentAddress() }, - }, - InitialPriority => { - title => 'InitialPriority', # loc - attribute => 'InitialPriority', - value => sub { return $_[0]->InitialPriority() }, + + # SubjectTag is special as we can not sort + SubjectTag => { + title => 'SubjectTag', # loc + value => sub { return $_[0]->SubjectTag }, }, - FinalPriority => { - title => 'FinalPriority', # loc - attribute => 'FinalPriority', - value => sub { return $_[0]->FinalPriority() }, + Sign => { + title => 'Sign', # loc + value => sub { return $_[0]->Sign? $_[0]->loc('yes') : $_[0]->loc('no') }, }, - DefaultDueIn => { - title => 'DefaultDueIn', # loc - attribute => 'DefaultDueIn', - value => sub { return $_[0]->DefaultDueIn() }, + Encrypt => { + title => 'Encrypt', # loc + value => sub { return $_[0]->Encrypt? $_[0]->loc('yes') : $_[0]->loc('no') }, }, }; +foreach my $field (qw( + Name Description CorrespondAddress CommentAddress + InitialPriority FinalPriority DefaultDueIn +)) { + $COLUMN_MAP->{$field} = { + title => $field, + attribute => $field, + value => sub { return $_[0]->$field() }, + }, +} + </%ONCE> <%INIT> $m->callback( COLUMN_MAP => $COLUMN_MAP, CallbackName => 'ColumnMap', CallbackOnce => 1 ); diff --git a/rt/share/html/Elements/RT__Scrip/ColumnMap b/rt/share/html/Elements/RT__Scrip/ColumnMap index 88b4c4bea..3e1d4074f 100644 --- a/rt/share/html/Elements/RT__Scrip/ColumnMap +++ b/rt/share/html/Elements/RT__Scrip/ColumnMap @@ -64,6 +64,10 @@ my $COLUMN_MAP = { return $_[0]->loc('Global'); }, }, + QueueId => { + title => 'Queue', # loc + value => sub { $_[0]->Queue }, + }, Condition => { title => 'Condition', # loc value => sub { return $_[0]->loc( $_[0]->ScripConditionObj->Name ) }, diff --git a/rt/share/html/Elements/RT__Template/ColumnMap b/rt/share/html/Elements/RT__Template/ColumnMap index 851cc9dec..e7c149575 100644 --- a/rt/share/html/Elements/RT__Template/ColumnMap +++ b/rt/share/html/Elements/RT__Template/ColumnMap @@ -67,6 +67,17 @@ my $COLUMN_MAP = { attribute => 'Description', value => sub { return $_[0]->Description() }, }, + Queue => { + title => 'Queue', # loc + value => sub { + return $_[0]->QueueObj->Name if $_[0]->Queue; + return $_[0]->loc('Global'); + }, + }, + QueueId => { + title => 'Queue', # loc + value => sub { $_[0]->Queue }, + }, }; </%ONCE> diff --git a/rt/share/html/Elements/RT__Ticket/ColumnMap b/rt/share/html/Elements/RT__Ticket/ColumnMap index 7df471009..c1f9e319a 100644 --- a/rt/share/html/Elements/RT__Ticket/ColumnMap +++ b/rt/share/html/Elements/RT__Ticket/ColumnMap @@ -303,26 +303,6 @@ $COLUMN_MAP = { value => sub { return \('<input type="checkbox" class="checkbox" name="UpdateTicket'.$_[0]->id.'" value="1" checked="checked" />') } }, - CustomField => { - attribute => sub { return shift @_ }, - title => sub { return pop @_ }, - value => sub { - # Display custom field contents, separated by newlines. - # For Image custom fields we also show a thumbnail here. - - my $values = $_[0]->CustomFieldValues( $_[-1] ); - my @values = map { - ( - ($_->CustomFieldObj->Type eq 'Image') - ? \($m->scomp( '/Elements/ShowCustomFieldImage', Object => $_ )) - : $_->Content - ), - \'<br />', - } @{ $values->ItemsArrayRef }; - pop @values; # Remove that last <br /> - return @values; - }, - }, Bookmark => { title => ' ', value => sub { @@ -335,8 +315,6 @@ $COLUMN_MAP = { }, }; -$COLUMN_MAP->{'CF'} = $COLUMN_MAP->{'CustomField'}; - # if no GPG support, then KeyOwnerName and KeyRequestors fall back to the regular # versions if (RT->Config->Get('GnuPG')->{'Enable'}) { diff --git a/rt/share/html/Elements/SelectQueue b/rt/share/html/Elements/SelectQueue index 20a5b7d9d..c78afe9ce 100755 --- a/rt/share/html/Elements/SelectQueue +++ b/rt/share/html/Elements/SelectQueue @@ -51,7 +51,7 @@ <input name="<%$Name%>" size="25" value="<%$d->Name%>" class="<%$Class%>" /> % } % else { -<select name="<%$Name%>" <% ($OnChange) ? 'onchange="'.$OnChange.'"' : '' |n %> class="<%$Class%>"> +<select name="<%$Name%>" <% ($Multiple) ? 'multiple="multiple"' : '' %> <% ($OnChange) ? 'onchange="'.$OnChange.'"' : '' |n %> class="<%$Class%>"> % if ($ShowNullOption) { <option value="">-</option> % } @@ -82,6 +82,7 @@ $NamedValues => 0 $Default => 0 $Lite => 0 $OnChange => undef +$Multiple => 0 $Class => 'select-queue' </%args> <%init> diff --git a/rt/share/html/Elements/ShowCustomFields b/rt/share/html/Elements/ShowCustomFields index ddb8b72e3..b60c49ae8 100644 --- a/rt/share/html/Elements/ShowCustomFields +++ b/rt/share/html/Elements/ShowCustomFields @@ -45,6 +45,7 @@ %# those contributions and any derivatives thereof. %# %# END BPS TAGGED BLOCK }}} +% $m->callback( CallbackName => 'BeforeCustomFields' ); % if ($Table) { <table> % } @@ -73,6 +74,7 @@ % if ($Table) { </table> % } +% $m->callback( CallbackName => 'AfterCustomFields', Object => $Object ); <%INIT> $m->callback( CallbackName => 'MassageCustomFields', @@ -82,9 +84,10 @@ $m->callback( my $print_value = sub { my ($cf, $value) = @_; - my $linked = $cf->LinkValueTo; - if ( $linked ) { - $m->out('<a href="'. $value->LinkValueTo .'" target="_new">'); + my $linked = $value->LinkValueTo; + if ( defined $linked && length $linked ) { + my $linked = $m->interp->apply_escapes( $linked, 'h' ); + $m->out('<a href="'. $linked .'" target="_new">'); } my $comp = "ShowCustomField". $cf->Type; $m->callback( @@ -98,7 +101,7 @@ my $print_value = sub { } else { $m->out( $m->interp->apply_escapes( $value->Content, 'h' ) ); } - $m->out('</a>') if $linked; + $m->out('</a>') if defined $linked && length $linked; # This section automatically populates a div with the "IncludeContentForValue" for this custom # field if it's been defined diff --git a/rt/share/html/Elements/ShowLinks b/rt/share/html/Elements/ShowLinks index 569bad39c..e3b3ef509 100755 --- a/rt/share/html/Elements/ShowLinks +++ b/rt/share/html/Elements/ShowLinks @@ -47,7 +47,7 @@ %# END BPS TAGGED BLOCK }}} <table> <tr> - <td class="labeltop"><&|/l&>Depends on</&>: (<a href="<%$clone->{'DependsOn-new'}%>"><% loc('Create') %></a>)</td> + <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Depends on'), Relation => 'DependsOn' &>: <span class="create">(<a href="<%$clone->{'DependsOn-new'}%>"><% loc('Create') %></a>)</span></td> <td class="value"> <%PERL> @@ -77,7 +77,7 @@ for my $link ( @{ $Ticket->DependsOn->ItemsArrayRef } ) { </td> </tr> <tr> - <td class="labeltop"><&|/l&>Depended on by</&>: (<a href="<%$clone->{'new-DependsOn'}%>"><% loc('Create') %></a>)</td> + <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Depended on by'), Relation => 'DependedOnBy' &>: <span class="create">(<a href="<%$clone->{'new-DependsOn'}%>"><% loc('Create') %></a>)</span></td> <td class="value"> <ul> % while (my $Link = $Ticket->DependedOnBy->Next) { @@ -87,15 +87,15 @@ for my $link ( @{ $Ticket->DependsOn->ItemsArrayRef } ) { </td> </tr> <tr> - <td class="labeltop"><&|/l&>Parents</&>: (<a href="<%$clone->{'MemberOf-new'}%>"><% loc('Create') %></a>)</td> + <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Parents'), Relation => 'Parents' &>: <span class="create">(<a href="<%$clone->{'MemberOf-new'}%>"><% loc('Create') %></a>)</span></td> <td class="value"><& /Ticket/Elements/ShowParents, Ticket => $Ticket &></td> </tr> <tr> - <td class="labeltop"><&|/l&>Children</&>: (<a href="<%$clone->{'new-MemberOf'}%>"><% loc('Create') %></a>)</td> + <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Children'), Relation => 'Children' &>: <span class="create">(<a href="<%$clone->{'new-MemberOf'}%>"><% loc('Create') %></a>)</span></td> <td class="value"><& /Ticket/Elements/ShowMembers, Ticket => $Ticket &></td> </tr> <tr> - <td class="labeltop"><&|/l&>Refers to</&>: (<a href="<%$clone->{'RefersTo-new'}%>"><% loc('Create') %></a>)</td> + <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Refers to'), Relation => 'RefersTo' &>: <span class="create">(<a href="<%$clone->{'RefersTo-new'}%>"><% loc('Create') %></a>)</span></td> <td class="value"> <ul> % while (my $Link = $Ticket->RefersTo->Next) { @@ -105,7 +105,7 @@ for my $link ( @{ $Ticket->DependsOn->ItemsArrayRef } ) { </td> </tr> <tr> - <td class="labeltop"><&|/l&>Referred to by</&>: (<a href="<%$clone->{'new-RefersTo'}%>"><% loc('Create') %></a>)</td> + <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Referred to by'), Relation => 'ReferredToBy' &>: <span class="create">(<a href="<%$clone->{'new-RefersTo'}%>"><% loc('Create') %></a>)</span></td> <td class="value"> <ul> % while (my $Link = $Ticket->ReferredToBy->Next) { @@ -124,14 +124,15 @@ for my $link ( @{ $Ticket->DependsOn->ItemsArrayRef } ) { <%INIT> +my $id = $Ticket->id; + my $clone = {}; my $path = RT->Config->Get('WebPath') . '/Ticket/Create.html?Queue=' . $Ticket->Queue . '&CloneTicket=' - . $Ticket->id; - + . $id; for my $relation ( qw(RefersTo ReferredToBy)) { @@ -142,15 +143,14 @@ for my $relation ( $clone->{$field} = $path . "&$field=" . join( '%20', - ( map { $_->$other() } @{ $Ticket->$relation->ItemsArrayRef } ), - $Ticket->id ); + ( map { $_->$other() } @{ $Ticket->$relation->ItemsArrayRef } ), $id ); } for my $relation ( qw(MemberOf Members DependsOn DependedOnBy)) { my $mode = $RT::Ticket::LINKTYPEMAP{$relation}->{Mode}; my $type = $RT::Ticket::LINKTYPEMAP{$relation}->{Type}; my $field = $mode eq 'Base' ? 'new-' . $type : $type . '-new'; - $clone->{$field} = $path . "&$field=". $Ticket->id ; + $clone->{$field} = $path . "&$field=$id"; } </%INIT> diff --git a/rt/share/html/Elements/ShowRelationLabel b/rt/share/html/Elements/ShowRelationLabel new file mode 100644 index 000000000..3c1ed1514 --- /dev/null +++ b/rt/share/html/Elements/ShowRelationLabel @@ -0,0 +1,62 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@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 }}} +<a href="<%$SearchURL |n %>"><%$Label%></a> +<%INIT> +my $typemap = RT::Ticket->LINKTYPEMAP->{$Relation}; +my $search_mode = $typemap->{Mode}; +my $search_type = $typemap->{Type}; +my $search_relation = RT::Ticket->LINKDIRMAP->{$search_type}{$search_mode}; + +my $Query = $search_relation . ' = ' . $id; +my $SearchURL = RT->Config->Get('WebPath') . '/Search/Results.html?' . $m->comp('/Elements/QueryString', Query => $Query); +</%INIT> +<%ARGS> +$id +$Label +$Relation +</%ARGS> diff --git a/rt/share/html/Elements/ShowUser b/rt/share/html/Elements/ShowUser index 2fbdcbc3e..01de7256a 100644 --- a/rt/share/html/Elements/ShowUser +++ b/rt/share/html/Elements/ShowUser @@ -49,18 +49,20 @@ <%INIT> # $User is an RT::User object # $Address is Email::Address object -if ( !$User && $Address ) { - $User = RT::User->new( $session{'CurrentUser'} ); - $User->LoadByEmail( $Address->address ); - unless ( $User->Id ) { - $m->comp( '/Elements/ShowUserVerbose', Address => $Address ); - return; - } + +my $comp = '/Elements/ShowUser'. ucfirst lc $style; +unless ( $m->comp_exists( $comp ) ) { + $RT::Logger->error( + 'Either system config or user #' + . $session{'CurrentUser'}->id + . ' picked UsernameFormat '. $style + . ', but '. $comp . "doesn't exist" + ); + return $m->comp('/Elements/ShowUserConcise', + User => $User, Address => $Address, + ); } -if ( $style eq 'concise' ) { - $m->comp( '/Elements/ShowUserConcise', User => $User ); -} -else { $m->comp( '/Elements/ShowUserVerbose', User => $User ); } +return $m->comp( $comp, User => $User, Address => $Address ); </%INIT> <%ARGS> $User => undef diff --git a/rt/share/html/Elements/ShowUserConcise b/rt/share/html/Elements/ShowUserConcise index 3cdba10dd..c4cccca75 100644 --- a/rt/share/html/Elements/ShowUserConcise +++ b/rt/share/html/Elements/ShowUserConcise @@ -46,7 +46,19 @@ %# %# END BPS TAGGED BLOCK }}} %# Released under the terms of version 2 of the GNU Public License -<% $User->RealName || $User->Name %>\ +<% $Address || $User->RealName || $User->Name %>\ <%ARGS> -$User +$User => undef +$Address => undef </%ARGS> +<%INIT> +if ( !$User && $Address ) { + $User = RT::User->new( $session{'CurrentUser'} ); + $User->LoadByEmail( $Address->address ); + if ( $User->Id ) { + $Address = ''; + } else { + $Address = $Address->address; + } +} +</%INIT> diff --git a/rt/share/html/Helpers/CalPopup.html b/rt/share/html/Helpers/CalPopup.html index 96e8d77d0..70b43c192 100644 --- a/rt/share/html/Helpers/CalPopup.html +++ b/rt/share/html/Helpers/CalPopup.html @@ -123,7 +123,17 @@ elsif ($DisplayedMonth == 1) { $prev_year--; } -my @cal = calendar($DisplayedMonth, $DisplayedYear); +my @cal; +{ + my $error; + # RT defines a __DIE__ and Calendar::Simple uses Carp::Croak to report errors + # work around this so we get a better error message if something is out of range + eval { local $SIG{__DIE__} = sub { $error = $_[0] }; @cal = calendar($DisplayedMonth, $DisplayedYear) }; + if ($error) { + $RT::Logger->error("error $error"); + $m->comp('/Elements/Error', Why => $error ); + } +} </%init> <%args> diff --git a/rt/share/html/NoAuth/Logout.html b/rt/share/html/NoAuth/Logout.html index 5a4926b97..7b80823b3 100755 --- a/rt/share/html/NoAuth/Logout.html +++ b/rt/share/html/NoAuth/Logout.html @@ -45,7 +45,7 @@ %# those contributions and any derivatives thereof. %# %# END BPS TAGGED BLOCK }}} -<& /Elements/Header, Title => loc('Logout'), Refresh => "1;URL=$URL" &> +<& /Elements/Header, Title => loc('Logout'), Refresh => RT->Config->Get('LogoutRefresh').";URL=$URL" &> </div> <div id="body" class="login-body"> @@ -58,22 +58,22 @@ <br /> <a href="<%$URL%>"><&|/l&>You're welcome to login again</&></a>. </&> + +% $m->callback( %ARGS ); + </div></div> <& /Elements/Footer, Menu => 0 &> % $m->abort(); <%INIT> +my $URL = RT->Config->Get('WebPath')."/"; $m->callback( %ARGS, CallbackName => 'BeforeSessionDelete' ); -if (defined %session) { +if (keys %session) { tied(%session)->delete; $session{'CurrentUser'} = RT::CurrentUser->new; } $m->callback( %ARGS, CallbackName => 'AfterSessionDelete' ); </%INIT> - -<%ARGS> -$URL => RT->Config->Get('WebPath')."/" -</%ARGS> diff --git a/rt/share/html/NoAuth/css/3.4-compat/misc.css b/rt/share/html/NoAuth/css/3.4-compat/misc.css index 2a58b13aa..a7a445f84 100644 --- a/rt/share/html/NoAuth/css/3.4-compat/misc.css +++ b/rt/share/html/NoAuth/css/3.4-compat/misc.css @@ -45,6 +45,9 @@ %# those contributions and any derivatives thereof. %# %# END BPS TAGGED BLOCK }}} + +@import "../base/misc.css"; + .oddline { background: white; } .evenline { background: #cecfef; } diff --git a/rt/share/html/NoAuth/css/3.4-compat/titlebox.css b/rt/share/html/NoAuth/css/3.4-compat/titlebox.css index 9b31b294b..72b1a27cb 100644 --- a/rt/share/html/NoAuth/css/3.4-compat/titlebox.css +++ b/rt/share/html/NoAuth/css/3.4-compat/titlebox.css @@ -77,10 +77,6 @@ color: black; } -.titlebox .titlebox-content hr.clear { - visibility: hidden; -} - %# TRS: I wish there was a more elegant way to do this... I essentially need to %# select all elements X that do NOT have element Y as a descendant... which I can %# fake with the child selector of CSS2, but IE is stupid and does not support that. diff --git a/rt/share/html/NoAuth/css/3.5-default/misc.css b/rt/share/html/NoAuth/css/3.5-default/misc.css index 67b5e1951..ca5020338 100755 --- a/rt/share/html/NoAuth/css/3.5-default/misc.css +++ b/rt/share/html/NoAuth/css/3.5-default/misc.css @@ -45,6 +45,9 @@ %# those contributions and any derivatives thereof. %# %# END BPS TAGGED BLOCK }}} + +@import "../base/misc.css"; + body { font-family: Verdana, sans-serif; font-size: 76%; @@ -52,8 +55,6 @@ body { background-color: white; } -.hide, .hidden { display: none !important; } - #body.calpopup { margin-left: 2em; } @@ -77,36 +78,11 @@ td { padding: 0.1em 0.5em 0.1em 0.5em; } -.clear { clear: both; } - ul.action-results { margin-top: 0; margin-bottom: 0; } -div.autocomplete { - position: absolute; - background-color: white; - border: 1px solid #888; - margin: 0px; - padding: 0px; -} -div.autocomplete ul { - list-style-type: none; - margin: 0px; - padding: 0px; -} -div.autocomplete ul li.selected { - background-color: #0088cc; - color: #eee; -} -div.autocomplete ul li { - list-style-type: none; - display: block; - margin: 0; - padding: 2px; -} - .shredder-form { line-height: 3em } .shredder-form span { margin-left: 1em; margin-right: 1em } .shredder-help { @@ -122,4 +98,3 @@ div.autocomplete ul li { #shredder-plugin-results input { margin-left: 1em; } .pod-sequence-C { background-color: #eee } - diff --git a/rt/share/html/NoAuth/css/3.5-default/titlebox.css b/rt/share/html/NoAuth/css/3.5-default/titlebox.css index 329cf8f76..f47b15803 100644 --- a/rt/share/html/NoAuth/css/3.5-default/titlebox.css +++ b/rt/share/html/NoAuth/css/3.5-default/titlebox.css @@ -152,10 +152,6 @@ text-decoration: underline; } -.titlebox .titlebox-content hr.clear { - visibility: hidden; -} - .titlebox .titlebox-title .left { position: relative; } diff --git a/rt/share/html/NoAuth/css/autohandler b/rt/share/html/NoAuth/css/autohandler index a92cfd17b..f11f78adb 100644 --- a/rt/share/html/NoAuth/css/autohandler +++ b/rt/share/html/NoAuth/css/autohandler @@ -49,7 +49,8 @@ my $file = $m->base_comp->source_file; if ($file =~ /\.(gif|png|jpe?g)$/i) { - RT::Interface::Web->SendStaticFile( File => $file ); + my $relfile = $m->base_comp->path; + RT::Interface::Web->SendStaticFile( File => $file, RelativeFile => $relfile ); } else { RT::Interface::Web::StaticFileHeaders(); $r->content_type('text/css') ; diff --git a/rt/share/html/NoAuth/css/base/misc.css b/rt/share/html/NoAuth/css/base/misc.css new file mode 100644 index 000000000..84023eca9 --- /dev/null +++ b/rt/share/html/NoAuth/css/base/misc.css @@ -0,0 +1,49 @@ +.hide, .hidden { display: none !important; } + +div.autocomplete { + position: absolute; + background-color: white; + border: 1px solid #888; + margin: 0px; + padding: 0px; +} +div.autocomplete ul { + list-style-type: none; + margin: 0px; + padding: 0px; +} +div.autocomplete ul li.selected { + background-color: #0088cc; + color: #eee; +} +div.autocomplete ul li { + list-style-type: none; + display: block; + margin: 0; + padding: 2px; +} + + +.clear { clear: both; } + +* html .clearfix { + height: 1%; /* IE5-6 */ +} +.clearfix { + display: inline-block; /* IE7xhtml*/ +} +html[xmlns] .clearfix { /* O */ + display: block; +} +.clearfix:after { /* FF, O, etc. */ + content: "."; + display: block; + height: 0; + clear: both; + visibility: hidden; +} + +.titlebox .titlebox-content hr.clear { + visibility: hidden; +} + diff --git a/rt/share/html/NoAuth/css/print.css b/rt/share/html/NoAuth/css/print.css index aaa1e8a2a..ae50342d8 100644 --- a/rt/share/html/NoAuth/css/print.css +++ b/rt/share/html/NoAuth/css/print.css @@ -80,7 +80,16 @@ div#header h1 { #header #page-menu, #header #actions-menu, #header #page-navigation, -.titlebox .title .widget, +.titlebox .titlebox-title .widget, +.ticket-info-links .titlebox-title .right, +.ticket-info-links .titlebox-content .labeltop .create, +.history .titlebox .titlebox-title .right, +.ticket-transaction .metadata .actions, +.ticket-transaction .content .downloadattachment, +#comp-Search-Results #body .refresh, +.search-result-actions, +#comp-Search-Chart #body div, +#comp-Search-Chart #body form, #footer { display: none; diff --git a/rt/share/html/NoAuth/css/web2/base.css b/rt/share/html/NoAuth/css/web2/base.css index b98253af9..a38854fb5 100644 --- a/rt/share/html/NoAuth/css/web2/base.css +++ b/rt/share/html/NoAuth/css/web2/base.css @@ -45,13 +45,6 @@ %# those contributions and any derivatives thereof. %# %# END BPS TAGGED BLOCK }}} -.hide { display: none; } -.clear { display: none;} - - - - - a { color: #000; text-decoration: none; diff --git a/rt/share/html/NoAuth/css/web2/boxes.css b/rt/share/html/NoAuth/css/web2/boxes.css index 0f2f20c2b..fbd9af108 100644 --- a/rt/share/html/NoAuth/css/web2/boxes.css +++ b/rt/share/html/NoAuth/css/web2/boxes.css @@ -160,10 +160,6 @@ } -.hidden { - display: none; -} - .titlebox .titlebox-title .widget a { display: block; margin: 0; @@ -190,3 +186,7 @@ .titlebox.rolled-up .titlebox-title .widget a { background-image: url(<%RT->Config->Get('WebPath')%>/NoAuth/images/css/rolldown-arrow.gif); } + +.titlebox hr.clear { + display: none; +} diff --git a/rt/share/html/NoAuth/css/web2/collection.css b/rt/share/html/NoAuth/css/web2/collection.css new file mode 100644 index 000000000..cbc8cefd7 --- /dev/null +++ b/rt/share/html/NoAuth/css/web2/collection.css @@ -0,0 +1,52 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@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 }}} + +table.collection td:first-child, table.collection th:first-child { + padding-left: 1em; +} + diff --git a/rt/share/html/NoAuth/css/web2/main.css b/rt/share/html/NoAuth/css/web2/main.css index 5ca561456..a47700354 100644 --- a/rt/share/html/NoAuth/css/web2/main.css +++ b/rt/share/html/NoAuth/css/web2/main.css @@ -62,6 +62,7 @@ @import "ticket.css"; @import "tools.css"; @import "admin.css"; +@import "collection.css"; @import "misc.css"; % $m->callback(CallbackName => 'End'); diff --git a/rt/share/html/NoAuth/css/web2/misc.css b/rt/share/html/NoAuth/css/web2/misc.css index eef5f4876..80d7ce0b4 100644 --- a/rt/share/html/NoAuth/css/web2/misc.css +++ b/rt/share/html/NoAuth/css/web2/misc.css @@ -45,6 +45,9 @@ %# those contributions and any derivatives thereof. %# %# END BPS TAGGED BLOCK }}} + +@import "../base/misc.css"; + #body.calpopup { margin-left: 1em; margin-top: 1em; @@ -71,29 +74,6 @@ font-size: 1.5em; } -div.autocomplete { - position: absolute; - background-color: white; - border: 1px solid #888; - margin: 0px; - padding: 0px; -} -div.autocomplete ul { - list-style-type: none; - margin: 0px; - padding: 0px; -} -div.autocomplete ul li.selected { - background-color: #0088cc; - color: #eee; -} -div.autocomplete ul li { - list-style-type: none; - display: block; - margin: 0; - padding: 2px; -} - .comment { padding-left: 0.5em; color: #999; @@ -105,4 +85,3 @@ div.autocomplete ul li { margin-top: 1em; overflow: auto; } - diff --git a/rt/share/html/NoAuth/css/web2/msie.css b/rt/share/html/NoAuth/css/web2/msie.css index 184ac1df5..2297c304a 100644 --- a/rt/share/html/NoAuth/css/web2/msie.css +++ b/rt/share/html/NoAuth/css/web2/msie.css @@ -237,3 +237,10 @@ table.queue-summary td, td.collection-as-table { #pick-criteria td.operator { width: 7.5em; } + +.plain-text-white-space { + word-wrap: break-word; /* Internet Explorer 5.5+ */ + white-space: pre; /* IE only hack to re-specify in addition to + word-wrap */ +} + diff --git a/rt/share/html/NoAuth/css/web2/portlets.css b/rt/share/html/NoAuth/css/web2/portlets.css index 947f49db2..d96d5a9f0 100644 --- a/rt/share/html/NoAuth/css/web2/portlets.css +++ b/rt/share/html/NoAuth/css/web2/portlets.css @@ -63,3 +63,9 @@ table.dashboard { } +.reminders blockquote { + margin-top: 0.5em; + margin-bottom: 0.5em; + margin-left: 1em; + margin-right: 1em; +} diff --git a/rt/share/html/NoAuth/images/autohandler b/rt/share/html/NoAuth/images/autohandler index 431a44f1d..7abf8b89e 100644 --- a/rt/share/html/NoAuth/images/autohandler +++ b/rt/share/html/NoAuth/images/autohandler @@ -3,5 +3,6 @@ # properly configured their webserver to stop RT from passing # images through the mason handler. my $file = $m->base_comp->source_file; -RT::Interface::Web->SendStaticFile( File => $file ); +my $relfile = $m->base_comp->path; +RT::Interface::Web->SendStaticFile( File => $file, RelativeFile => $relfile ); </%INIT> diff --git a/rt/share/html/NoAuth/js/autohandler b/rt/share/html/NoAuth/js/autohandler index 74028f8c6..e81415433 100644 --- a/rt/share/html/NoAuth/js/autohandler +++ b/rt/share/html/NoAuth/js/autohandler @@ -51,7 +51,8 @@ my $type; my $file = $m->base_comp->source_file; if ($file =~ /\.(gif|png|jpe?g)$/i) { - RT::Interface::Web->SendStaticFile( File => $file ); + my $relfile = $m->base_comp->path; + RT::Interface::Web->SendStaticFile( File => $file, RelativeFile => $relfile ); } else { &RT::Interface::Web::StaticFileHeaders(); $r->content_type('application/x-javascript'); diff --git a/rt/share/html/NoAuth/rss/dhandler b/rt/share/html/NoAuth/rss/dhandler new file mode 100644 index 000000000..c402b6f8e --- /dev/null +++ b/rt/share/html/NoAuth/rss/dhandler @@ -0,0 +1,48 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@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 }}} +<& /Search/Elements/ResultsRSSView, %ARGS &> diff --git a/rt/share/html/Search/Bulk.html b/rt/share/html/Search/Bulk.html index fa20e331c..f2ca45c26 100755 --- a/rt/share/html/Search/Bulk.html +++ b/rt/share/html/Search/Bulk.html @@ -163,7 +163,9 @@ <input type="submit" class="button" name="AddMoreAttach" value="<&|/l&>Add More Files</&>" /> <input type="hidden" class="hidden" name="UpdateAttach" value="1" /></td></tr> <tr><td class="labeltop"><&|/l&>Message</&>:</td><td> - <& /Elements/MessageBox, Name=>"UpdateContent"&> +%# 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", IncludeSignature => $IncludeSignature &> </td></tr> </table> diff --git a/rt/share/html/Search/Chart b/rt/share/html/Search/Chart index 59e9fc6fc..abee3e52a 100644 --- a/rt/share/html/Search/Chart +++ b/rt/share/html/Search/Chart @@ -66,52 +66,11 @@ if ($ChartStyle eq 'pie') { use RT::Report::Tickets; my $tix = RT::Report::Tickets->new( $session{'CurrentUser'} ); + my ($count_name, $value_name) = $tix->SetupGroupings( Query => $Query, GroupBy => $PrimaryGroupBy, ); -my $chart = $chart_class->new( 600 => 400 ); - -my $font = RT->Config->Get('ChartFont') || ['verdana', 'arial', gdMediumBoldFont]; -$chart->set_title_font( $font, 12 ) if $chart->can('set_title_font'); -$chart->set_legend_font( $font, 12 ) if $chart->can('set_legend_font'); -$chart->set_x_label_font( $font, 10 ) if $chart->can('set_x_label_font'); -$chart->set_y_label_font( $font, 10 ) if $chart->can('set_y_label_font'); -$chart->set_label_font( $font, 10 ) if $chart->can('set_label_font'); -$chart->set_x_axis_font( $font, 9 ) if $chart->can('set_x_axis_font'); -$chart->set_y_axis_font( $font, 9 ) if $chart->can('set_y_axis_font'); -$chart->set_values_font( $font, 9 ) if $chart->can('set_values_font'); -$chart->set_value_font( $font, 9 ) if $chart->can('set_value_font'); - -# Pie charts don't like having no input, so we show a special image -# that indicates an error message. Because this is used in an <img> -# context, it can't be a simple error message. Without this check, -# the chart will just be a non-loading image. -if ($tix->Count == 0) { - my $plot = GD::Image->new(600 => 400); - $plot->colorAllocate(255, 255, 255); # background - my $black = $plot->colorAllocate(0, 0, 0); - - require GD::Text::Wrap; - my $error = GD::Text::Wrap->new($plot, - color => $black, - text => loc("No tickets found."), - ); - $error->set_font( $font, 12 ); - $error->draw(0, 0); - - $m->comp( 'SELF:Plot', plot => $plot, %ARGS ); -} - -if ($chart_class eq "GD::Graph::bars") { - $chart->set( - x_label => $tix->Label( $PrimaryGroupBy ), - x_labels_vertical => 1, - y_label => loc('Tickets'), - show_values => 1 - ); -} - my %class = ( Queue => 'RT::Queue', Owner => 'RT::User', @@ -121,15 +80,17 @@ my %class = ( my $class = $class{ $PrimaryGroupBy }; my %data; +my $max_value = 0; +my $max_key_length = 0; while ( my $entry = $tix->Next ) { my $key; if ( $class ) { my $q = $class->new( $session{'CurrentUser'} ); - $q->Load( $entry->__Value( $value_name ) ); + $q->Load( $entry->LabelValue( $value_name ) ); $key = $q->Name; } else { - $key = $entry->__Value($value_name); + $key = $entry->LabelValue($value_name); } $key ||= '(no value)'; @@ -140,26 +101,84 @@ while ( my $entry = $tix->Next ) { $key = loc($key); } $data{ $key } = $value; -} - -# XXX: Convert 1970-01-01 date to the 'Not Set' -# this code should be generalized!!! -if ( $PrimaryGroupBy =~ /(Daily|Monthly|Annually)$/ ) { - my $re; - $re = qr{1970-01-01} if $PrimaryGroupBy =~ /Daily$/; - $re = qr{1970-01} if $PrimaryGroupBy =~ /Monthly$/; - $re = qr{1970} if $PrimaryGroupBy =~ /Annually$/; - foreach my $k (keys %data) { - my $tmp = $k; - $tmp =~ s/^$re/loc('Not Set')/e or next; - $data{$tmp} = delete $data{$k}; - } + $max_value = $value if $max_value < $value; + $max_key_length = length $key if $max_key_length < length $key; } unless (keys %data) { $data{''} = 0; } + +my $chart = $chart_class->new( 600 => 400 ); +$chart->set( pie_height => 60 ) if $chart_class eq 'GD::Graph::pie'; +my %font_config = RT->Config->Get('ChartFont'); +my $font = $font_config{ $session{CurrentUser}->UserObj->Lang || '' } + || $font_config{'others'}; +$chart->set_title_font( $font, 16 ) if $chart->can('set_title_font'); +$chart->set_legend_font( $font, 16 ) if $chart->can('set_legend_font'); +$chart->set_x_label_font( $font, 14 ) if $chart->can('set_x_label_font'); +$chart->set_y_label_font( $font, 14 ) if $chart->can('set_y_label_font'); +$chart->set_label_font( $font, 14 ) if $chart->can('set_label_font'); +$chart->set_x_axis_font( $font, 12 ) if $chart->can('set_x_axis_font'); +$chart->set_y_axis_font( $font, 12 ) if $chart->can('set_y_axis_font'); +$chart->set_values_font( $font, 12 ) if $chart->can('set_values_font'); +$chart->set_value_font( $font, 12 ) if $chart->can('set_value_font'); + +# Pie charts don't like having no input, so we show a special image +# that indicates an error message. Because this is used in an <img> +# context, it can't be a simple error message. Without this check, +# the chart will just be a non-loading image. +if ($tix->Count == 0) { + my $plot = GD::Image->new(600 => 400); + $plot->colorAllocate(255, 255, 255); # background + my $black = $plot->colorAllocate(0, 0, 0); + + require GD::Text::Wrap; + my $error = GD::Text::Wrap->new($plot, + color => $black, + text => loc("No tickets found."), + ); + $error->set_font( $font, 16 ); + $error->draw(0, 0); + + $m->comp( 'SELF:Plot', plot => $plot, %ARGS ); +} + +if ($chart_class eq "GD::Graph::bars") { + $chart->set( + x_label => $tix->Label( $PrimaryGroupBy ), + y_label => loc('Tickets'), + show_values => 1, + bar_spacing => 5, + bargroup_spacing => 10, + x_label_position => 0.6, + y_label_position => 0.6, + values_space => -1, +# the following line to make sure there's enough space for values to show + y_max_value => 5*(int($max_value/5) + 2), +# if there're too many bars or at least one key is too long, use vertical + x_labels_vertical => ( keys(%data) * $max_key_length > 60 ) ? 1 : 0, + ); +} + +# refine values' colors, with both Color::Scheme's help and my own tweak +$chart->{dclrs} = [ + '66cc66', 'ff6666', 'ffcc66', '663399', + '3333cc', + '339933', '993333', '996633', '663399', + '33cc33', 'cc3333', 'cc9933', '6633cc' +]; + +{ + no warnings 'redefine'; + *GD::Graph::pick_data_clr = sub { + my $self = shift; + my $color_hex = $self->{dclrs}[ $_[0] % @{ $self->{dclrs} } - 1 ]; + return map { hex } ( $color_hex =~ /(..)(..)(..)/ ); + }; +} + my $plot = $chart->plot( [ [sort keys %data], [map $data{$_}, sort keys %data] ] ) or die $chart->error; $m->comp( 'SELF:Plot', plot => $plot, %ARGS ); </%init> @@ -170,7 +189,6 @@ $plot => undef </%ARGS> <%INIT> my @types = ('png', 'gif'); - for my $type (@types) { $plot->can($type) or next; diff --git a/rt/share/html/Search/Elements/Chart b/rt/share/html/Search/Elements/Chart index 3db92c4d8..bf4cd0c1c 100644 --- a/rt/share/html/Search/Elements/Chart +++ b/rt/share/html/Search/Elements/Chart @@ -72,28 +72,16 @@ my (@keys, @values); while ( my $entry = $tix->Next ) { if ($class) { my $q = $class->new( $session{'CurrentUser'} ); - $q->Load( $entry->__Value( $value_name ) ); + $q->Load( $entry->LabelValue( $value_name ) ); push @keys, $q->Name; } else { - push @keys, $entry->__Value( $value_name ); + push @keys, $entry->LabelValue( $value_name ); } $keys[-1] ||= loc('(no value)'); push @values, $entry->__Value( $count_name ); } -# XXX: Convert 1970-01-01 date to the 'Not Set' -# this code should be generalized!!! -if ( $PrimaryGroupBy =~ /(Daily|Monthly|Annually)$/ ) { - my $re; - $re = qr{1970-01-01} if $PrimaryGroupBy =~ /Daily$/; - $re = qr{1970-01} if $PrimaryGroupBy =~ /Monthly$/; - $re = qr{1970} if $PrimaryGroupBy =~ /Annually$/; - foreach (@keys) { - s/^$re/loc('Not Set')/e; - } -} - my %data; my %loc_keys; foreach my $key (@keys) { $data{$key} = shift @values; $loc_keys{$key} = loc($key); } @@ -126,7 +114,23 @@ my $query_string = $m->comp('/Elements/QueryString', %ARGS); % $total += $value; <tr class="<%$i%2 ? 'evenline' : 'oddline' %>"> <td class="label collection-as-table"> -<%$key%> +%# TODO sadly we don't have "creator.city is null" or alike support yet +%# so no link if the key is undef for now +% if ( $PrimaryGroupBy !~ /(Hourly|Daily|Monthly|Annually)$/ +% && $key ne loc('(no value)') ) { +% my $group = $PrimaryGroupBy; $group =~ s! !.!; +% my %orig_keys = reverse %loc_keys; +% my $QueryString = $m->comp('/Elements/QueryString', +% Query => "$Query and $group = '$orig_keys{$key}'", +% Format => $ARGS{Format}, +% Rows => $ARGS{Rows}, +% OrderBy => $ARGS{OrderBy}, +% Order => $ARGS{Order}, +% ); +<a href=<% RT->Config->Get('WebURL') %>Search/Results.html?<%$QueryString%>><%$key%></a> +% } else { +<% $key %> +% } </td> <td class="value collection-as-table"> <%$value%> diff --git a/rt/share/html/Search/Elements/ResultsRSSView b/rt/share/html/Search/Elements/ResultsRSSView new file mode 100644 index 000000000..f335411f8 --- /dev/null +++ b/rt/share/html/Search/Elements/ResultsRSSView @@ -0,0 +1,143 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@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 }}} +<%INIT> +use Encode (); + +my $old_current_user; + +if ( $m->request_comp->path =~ RT->Config->Get('WebNoAuthRegex') ) { + my $path = $m->dhandler_arg; + + my $notfound = sub { + my $mesg = shift; + $r->headers_out->{'Status'} = '404 Not Found'; + $RT::Logger->info("Error encountered in rss generation: $mesg"); + $m->clear_and_abort; + }; + + $notfound->("Invalid path: $path") unless $path =~ m!^([^/]+)/([^/]+)/?!; + + my ( $name, $auth ) = ( $1, $2 ); + + # Unescape parts + $name =~ s/\%([0-9a-z]{2})/chr(hex($1))/gei; + + # convert to perl strings + $name = Encode::decode_utf8($name); + + my $user = RT::User->new($RT::SystemUser); + $user->Load($name); + $notfound->("Invalid user: $user") unless $user->id; + + $notfound->("Invalid authstring") + unless $user->ValidateAuthString( $auth, + $ARGS{Query} . $ARGS{Order} . $ARGS{OrderBy} ); + + $old_current_user = $session{'CurrentUser'}; + my $cu = RT::CurrentUser->new; + $cu->Load($user); + $session{'CurrentUser'} = $cu; +} + +my $Tickets = RT::Tickets->new($session{'CurrentUser'}); +$Tickets->FromSQL($ARGS{'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); +} +$r->content_type('application/rss+xml'); + + + + # create an RSS 1.0 file (http://purl.org/rss/1.0/) + use XML::RSS; + my $rss = new XML::RSS (version => '1.0'); + $rss->channel( + title => RT->Config->Get('rtname').": Search " . $ARGS{'Query'}, + link => RT->Config->Get('WebURL'), + description => "", + dc => { + }, + generator => "RT v" . $RT::VERSION, + syn => { + updatePeriod => "hourly", + updateFrequency => "1", + updateBase => "1901-01-01T00:00+00:00", + }, + ); + + + while ( my $Ticket = $Tickets->Next()) { + my $creator_str = $m->scomp('/Elements/ShowUser', User => $Ticket->CreatorObj); + $creator_str =~ s/[\r\n]//g; + $rss->add_item( + title => $Ticket->Subject || loc('No Subject'), + link => RT->Config->Get('WebURL')."Ticket/Display.html?id=".$Ticket->id, + description => $Ticket->Transactions->First->Content, + dc => { creator => $creator_str, + date => $Ticket->CreatedObj->RFC2822, + }, + guid => $Ticket->Queue . '_' . $Ticket->id, + ); + } + +$m->out($rss->as_string); +$session{'CurrentUser'} = $old_current_user if $old_current_user; +$m->abort(); +</%INIT> +<%ARGS> +$OrderBy => 'Created' +$Order => 'ASC' +</%ARGS> + diff --git a/rt/share/html/Search/Results.html b/rt/share/html/Search/Results.html index 13252eebb..22858f172 100755 --- a/rt/share/html/Search/Results.html +++ b/rt/share/html/Search/Results.html @@ -84,6 +84,7 @@ </div> <div align="right" class="search-result-actions"> <& Elements/ResultViews, + Collection => $session{'tickets'}, QueryString => $QueryString, Query => $Query, Format => $Format, @@ -118,6 +119,7 @@ if ( !defined($Rows) ) { $Rows = 50; } } +$Page = 1 unless $Page && $Page > 0; my ($title, $ticketcount); $session{'i'}++; @@ -134,6 +136,8 @@ if ($OrderBy =~ /\|/) { } else { $session{'tickets'}->OrderBy(FIELD => $OrderBy, ORDER => $Order); } +$session{'tickets'}->RowsPerPage( $Rows ) if $Rows; +$session{'tickets'}->GotoPage( $Page - 1 ); $session{'CurrentSearchHash'} = { Format => $Format, @@ -142,7 +146,7 @@ $session{'CurrentSearchHash'} = { Order => $Order, OrderBy => $OrderBy, RowsPerPage => $Rows - }; +}; if ( $session{'tickets'}->Query()) { @@ -161,7 +165,10 @@ my $QueryString = "?".$m->comp('/Elements/QueryString', Page => $Page); my $ShortQueryString = "?".$m->comp('/Elements/QueryString', Query => $Query); my $RSSQueryString = "?".$m->comp('/Elements/QueryString', Query => $Query, Order => $Order, OrderBy => $OrderBy); -my $RSSFeedURL = RT->Config->Get('WebPath')."/Search/Results.rdf$RSSQueryString"; +my $RSSPath = join '/', map $m->interp->apply_escapes($_, 'u'), + $session{'CurrentUser'}->UserObj->Name, + $session{'CurrentUser'}->UserObj->GenerateAuthString( $Query.$Order.$OrderBy ); +my $RSSFeedURL = RT->Config->Get('WebPath')."/NoAuth/rss/$RSSPath/$RSSQueryString"; if ($ARGS{'TicketsRefreshInterval'}) { $session{'tickets_refresh_interval'} = $ARGS{'TicketsRefreshInterval'}; diff --git a/rt/share/html/Search/Results.rdf b/rt/share/html/Search/Results.rdf index 0a1943059..c402b6f8e 100644 --- a/rt/share/html/Search/Results.rdf +++ b/rt/share/html/Search/Results.rdf @@ -45,59 +45,4 @@ %# those contributions and any derivatives thereof. %# %# END BPS TAGGED BLOCK }}} -<%INIT> - -my $Tickets = RT::Tickets->new($session{'CurrentUser'}); -$Tickets->FromSQL($ARGS{'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); -} -$r->content_type('application/rss+xml'); - - - - # create an RSS 1.0 file (http://purl.org/rss/1.0/) - use XML::RSS; - my $rss = new XML::RSS (version => '1.0'); - $rss->channel( - title => RT->Config->Get('rtname').": Search" . $ARGS{'Query'}, - link => RT->Config->Get('WebURL'), - description => "", - dc => { - }, - generator => "RT v" . $RT::VERSION, - syn => { - updatePeriod => "hourly", - updateFrequency => "1", - updateBase => "1901-01-01T00:00+00:00", - }, - ); - - - while ( my $Ticket = $Tickets->Next()) { - my $creator_str = $m->scomp('/Elements/ShowUser', User => $Ticket->CreatorObj); - $creator_str =~ s/[\r\n]//g; - $rss->add_item( - title => $Ticket->Subject || loc('No Subject'), - link => RT->Config->Get('WebURL')."Ticket/Display.html?id=".$Ticket->id, - description => $Ticket->Transactions->First->Content, - dc => { creator => $creator_str, - date => $Ticket->CreatedObj->RFC2822, - }, - guid => $Ticket->Queue . '_' . $Ticket->id, - ); - } -$m->out($rss->as_string); -$m->abort(); -</%INIT> -<%ARGS> -$OrderBy => 'Created' -$Order => 'ASC' -</%ARGS> +<& /Search/Elements/ResultsRSSView, %ARGS &> diff --git a/rt/share/html/Search/Results.tsv b/rt/share/html/Search/Results.tsv index bb3ac4482..946a35d02 100644 --- a/rt/share/html/Search/Results.tsv +++ b/rt/share/html/Search/Results.tsv @@ -107,7 +107,7 @@ $r->content_type('application/vnd.ms-excel'); $_ += @header - 1 foreach values %cf_name_to_pos; - foreach my $name ( sort { $cf_name_to_pos{$a} <=> $cf_name_to_pos{$a} } keys %cf_name_to_pos ) { + foreach my $name ( sort { $cf_name_to_pos{$a} <=> $cf_name_to_pos{$b} } keys %cf_name_to_pos ) { push @header, "CF-". $name; } $m->out(join("\t", @header)); diff --git a/rt/share/html/SelfService/Error.html b/rt/share/html/SelfService/Error.html index 9c81ebbe6..8956c3ea1 100755 --- a/rt/share/html/SelfService/Error.html +++ b/rt/share/html/SelfService/Error.html @@ -66,6 +66,6 @@ $Why => loc("the calling component did not specify why") </%args> <%INIT> -$Details ||= "No details"; +$Details ||= loc("No details"); $RT::Logger->error("WebRT: $Why ($Details)"); </%INIT> diff --git a/rt/share/html/SelfService/Prefs.html b/rt/share/html/SelfService/Prefs.html index dabab7937..468a3d508 100755 --- a/rt/share/html/SelfService/Prefs.html +++ b/rt/share/html/SelfService/Prefs.html @@ -50,13 +50,14 @@ <& /Elements/ListActions, actions => \@results &> <form method="post"> -% unless (RT->Config->Get('WebExternalAuth') and !RT->Config->Get('WebFallbackToInternalAuth')) { <&| /Widgets/TitleBox, title => loc('Change password') &> -<&|/l&>New password</&>: <input type="password" name="NewPass1" size="16" autocomplete="off" /> -<&|/l&>Confirm</&>: <input type="password" name="NewPass2" size="16" autocomplete="off" /> +<& /Elements/EditPassword, + User => $user, + Name => [qw(CurrentPass NewPass1 NewPass2)], +&> </&> + <br /> -% } <& /Elements/Submit, Label => loc('Save Changes') &> </form> @@ -64,29 +65,32 @@ <%INIT> my @results; -if ($NewPass1) { - if ($NewPass1 ne $NewPass2) { - push (@results, "Passwords did not match."); - } - else { - my ($val, $msg)=$session{'CurrentUser'}->UserObj->SetPassword($NewPass1); - push (@results, "Password: ".$msg); - } +my $user = $session{'CurrentUser'}->UserObj; + +if (defined $NewPass1 && length $NewPass1 ) { + my ($status, $msg) = $user->SafeSetPassword( + Current => $CurrentPass, + New => $NewPass1, + Confirmation => $NewPass2, + ); + push @results, loc("Password: [_1]", $msg); } + if ($Signature) { $Signature =~ s/(\r\n|\r)/\n/g; - if ($Signature ne $session{'CurrentUser'}->UserObj->Signature) { - my ($val, $msg)=$session{'CurrentUser'}->UserObj->SetSignature($Signature); + if ($Signature ne $user->Signature) { + my ($val, $msg) = $user->SetSignature($Signature); push (@results, "Signature: ".$msg); } } -#A hack to make sure that session gets rewritten. +#A hack to make sure that session gets rewritten. $session{'i'}++; </%INIT> <%ARGS> $Signature => undef +$CurrentPass => undef $NewPass1 => undef $NewPass2 => undef </%ARGS> diff --git a/rt/share/html/Ticket/Attachment/dhandler b/rt/share/html/Ticket/Attachment/dhandler index d4d556b24..8b41329ba 100755 --- a/rt/share/html/Ticket/Attachment/dhandler +++ b/rt/share/html/Ticket/Attachment/dhandler @@ -68,8 +68,11 @@ } my $content_type = $AttachmentObj->ContentType || 'text/plain'; - - unless (RT->Config->Get('TrustHTMLAttachments')) { + + if (RT->Config->Get('AlwaysDownloadAttachments')) { + $r->headers_out->{'Content-Disposition'} = "attachment; filename=" . $AttachmentObj->Filename; + } + elsif (!RT->Config->Get('TrustHTMLAttachments')) { $content_type = 'text/plain' if ($content_type =~ /^text\/html/i); } diff --git a/rt/share/html/Ticket/Create.html b/rt/share/html/Ticket/Create.html index 28b655691..2c8e35778 100755 --- a/rt/share/html/Ticket/Create.html +++ b/rt/share/html/Ticket/Create.html @@ -112,6 +112,7 @@ </td> <td class="value" colspan="5"> <input name="Subject" size="60" maxsize="200" value="<%$ARGS{Subject} || ''%>" /> +% $m->callback( %ARGS, CallbackName => 'AfterSubject' ); </td> </tr> <tr> @@ -158,6 +159,7 @@ % } else { <& /Elements/MessageBox, QuoteTransaction => $QuoteTransaction &> %} +% $m->callback( %ARGS, QueueObj => $QueueObj, CallbackName => 'AfterMessageBox' ); <br /> </td> @@ -392,6 +394,22 @@ if ( !exists $ARGS{'AddMoreAttach'} && ($ARGS{'id'}||'') eq 'new' ) { $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 ); diff --git a/rt/share/html/Ticket/Elements/EditCustomFields b/rt/share/html/Ticket/Elements/EditCustomFields index c3a44ee22..5478c7871 100755 --- a/rt/share/html/Ticket/Elements/EditCustomFields +++ b/rt/share/html/Ticket/Elements/EditCustomFields @@ -45,6 +45,7 @@ %# those contributions and any derivatives thereof. %# %# END BPS TAGGED BLOCK }}} +% $m->callback( %ARGS, CallbackName => 'BeforeCustomFields' ); <table> % my $i = 0; % while ( my $CustomField = $CustomFields->Next ) { @@ -85,6 +86,7 @@ % } </table> +% $m->callback( %ARGS, CallbackName => 'AfterCustomFields', TicketObj => $TicketObj, QueueObj => $QueueObj ); <%INIT> my $CustomFields; diff --git a/rt/share/html/Ticket/Elements/EditDates b/rt/share/html/Ticket/Elements/EditDates index fc17cdbd4..e6f724f7b 100755 --- a/rt/share/html/Ticket/Elements/EditDates +++ b/rt/share/html/Ticket/Elements/EditDates @@ -70,6 +70,7 @@ <& /Elements/SelectDate, menu_prefix => 'Due', current => 0 &> (<% $TicketObj->DueObj->AsString %>) </td> </tr> +% $m->callback( %ARGS, CallbackName => 'EndOfList', Ticket => $TicketObj ); </table> <%ARGS> $TicketObj => undef diff --git a/rt/share/html/Ticket/Elements/EditTransactionCustomFields b/rt/share/html/Ticket/Elements/EditTransactionCustomFields index 8bf939db6..a58dded9b 100644 --- a/rt/share/html/Ticket/Elements/EditTransactionCustomFields +++ b/rt/share/html/Ticket/Elements/EditTransactionCustomFields @@ -45,6 +45,7 @@ %# those contributions and any derivatives thereof. %# %# END BPS TAGGED BLOCK }}} +% $m->callback( CallbackName => 'BeforeTransactionCustomFields', TicketObj => $TicketObj, QueueObj => $QueueObj, NamePrefix => $NamePrefix ); % if ($CustomFields->Count) { % while (my $CF = $CustomFields->Next()) { % next unless $CF->CurrentUserHasRight('ModifyCustomField'); @@ -60,6 +61,7 @@ </td></tr> % } % } +% $m->callback( CallbackName => 'AfterTransactionCustomFields', TicketObj => $TicketObj, QueueObj => $QueueObj, NamePrefix => $NamePrefix ); <%INIT> my $CustomFields; diff --git a/rt/share/html/Ticket/Elements/PreviewScrips b/rt/share/html/Ticket/Elements/PreviewScrips index 7480adecf..d376f5d08 100755 --- a/rt/share/html/Ticket/Elements/PreviewScrips +++ b/rt/share/html/Ticket/Elements/PreviewScrips @@ -69,7 +69,11 @@ my @non_recipients = @{ $squelch{'EmailAddresses'} }; %my @addresses = $scrip->ActionObj->Action->$type(); <ul> %foreach my $addr (@addresses) { -<li> <b><%loc($type)%></b>: <input type="checkbox" class="checkbox" name="Ticket-<%$TicketObj->id%>-SquelchMailTo" value="<%$addr->address%>" /> <%$addr->address%> +<li> + <b><%loc($type)%></b>: <input type="checkbox" class="checkbox" name="Ticket-<%$TicketObj->id%>-SquelchMailTo" value="<%$addr->address%>" /> <%$addr->address%> + +% $m->callback(CallbackName => 'AfterAddress', Ticket => $TicketObj, Address => $addr, Type => $type); +</li> % } </ul> % } diff --git a/rt/share/html/Ticket/Elements/ShowAttachments b/rt/share/html/Ticket/Elements/ShowAttachments index 72298d79f..ab0d92112 100755 --- a/rt/share/html/Ticket/Elements/ShowAttachments +++ b/rt/share/html/Ticket/Elements/ShowAttachments @@ -61,11 +61,22 @@ my $size = $rev->ContentLength; if ($size) { - if ($size > 1024) { - $size = int($size/102.4)/10 . "k"; + my $kb = int($size/102.4) / 10; + my $units = RT->Config->Get('AttachmentUnits'); + + if (!defined($units)) { + if ($size > 1024) { + $size = $kb . "k"; + } + else { + $size = $size . "b"; + } + } + elsif ($units eq 'k') { + $size = $kb . "k"; } else { - $size = $size ."b"; + $size = $size . "b"; } </%PERL> diff --git a/rt/share/html/Ticket/Elements/ShowDates b/rt/share/html/Ticket/Elements/ShowDates index d309907dc..07140c2e4 100755 --- a/rt/share/html/Ticket/Elements/ShowDates +++ b/rt/share/html/Ticket/Elements/ShowDates @@ -84,6 +84,7 @@ <td class="value date updated"><% $UpdatedString | h %></td> % } </tr> +% $m->callback( %ARGS, CallbackName => 'EndOfList', TicketObj => $Ticket ); </table> <%ARGS> $Ticket => undef diff --git a/rt/share/html/Ticket/Elements/ShowGroupMembers b/rt/share/html/Ticket/Elements/ShowGroupMembers index a15f850b4..6597cc543 100644 --- a/rt/share/html/Ticket/Elements/ShowGroupMembers +++ b/rt/share/html/Ticket/Elements/ShowGroupMembers @@ -50,7 +50,9 @@ % my $Users = $Group->UserMembersObj( Recursively => $Recursively ); % while ( my $user = $Users->Next ) { <& /Elements/ShowUser, User => $user, Ticket => $Ticket &> -<& /Elements/ShowUserEmailFrequency, User => $user, Ticket => $Ticket &><br /> +<& /Elements/ShowUserEmailFrequency, User => $user, Ticket => $Ticket &> +% $m->callback( User => $user, Ticket => $Ticket, %ARGS, CallbackName => 'AboutThisUser' ); +<br /> % } % my $Groups = $Group->GroupMembersObj( Recursively => $Recursively ); % $Groups->LimitToUserDefinedGroups; diff --git a/rt/share/html/Ticket/Elements/ShowMessageStanza b/rt/share/html/Ticket/Elements/ShowMessageStanza index 0d4fe6154..9d2f21120 100755 --- a/rt/share/html/Ticket/Elements/ShowMessageStanza +++ b/rt/share/html/Ticket/Elements/ShowMessageStanza @@ -48,7 +48,8 @@ <%perl> if ( ref $Message ) { $m->out('<pre>') if $plain_text_pre && !$Depth && !$plain_text_mono; - $m->out( qq{<div class="message-stanza-depth-$Depth">} ); + $m->out( qq{<div class="message-stanza-depth-$Depth } .($plain_text_mono ? "plain-text-white-space" : "") .qq{">} ); + my @stack; my $para = ''; diff --git a/rt/share/html/Ticket/Elements/ShowPeople b/rt/share/html/Ticket/Elements/ShowPeople index ddd2e3c6f..1f0e5319e 100755 --- a/rt/share/html/Ticket/Elements/ShowPeople +++ b/rt/share/html/Ticket/Elements/ShowPeople @@ -50,7 +50,9 @@ <td class="label"><&|/l&>Owner</&>:</td> % my $owner = $Ticket->OwnerObj; <td class="value"><& /Elements/ShowUser, User => $owner, Ticket => $Ticket &> - <& /Elements/ShowUserEmailFrequency, User => $owner, Ticket => $Ticket &></td> + <& /Elements/ShowUserEmailFrequency, User => $owner, Ticket => $Ticket &> +% $m->callback( User => $owner, Ticket => $Ticket, %ARGS, CallbackName => 'AboutThisUser' ); + </td> </tr> <tr> <td class="labeltop"><&|/l&>Requestors</&>:</td> diff --git a/rt/share/html/Ticket/Elements/ShowSummary b/rt/share/html/Ticket/Elements/ShowSummary index 4c2d54e5e..21c53c594 100755 --- a/rt/share/html/Ticket/Elements/ShowSummary +++ b/rt/share/html/Ticket/Elements/ShowSummary @@ -45,73 +45,82 @@ %# those contributions and any derivatives thereof. %# %# END BPS TAGGED BLOCK }}} - <table width="100%" class="ticket-summary"> - <tr> - <td valign="top" class="boxcontainer"> - <&| /Widgets/TitleBox, title => loc('The Basics'), - title_href => RT->Config->Get('WebPath')."/Ticket/Modify.html?id=".$Ticket->Id, - class => 'ticket-info-basics' &> - <& /Ticket/Elements/ShowBasics, Ticket => $Ticket &> - </&> +<table width="100%" class="ticket-summary"> +<tr> + <td valign="top" class="boxcontainer"> +% $m->callback( %ARGS, CallbackName => 'LeftColumnTop' ); + + <&| /Widgets/TitleBox, title => loc('The Basics'), + title_href => RT->Config->Get('WebPath')."/Ticket/Modify.html?id=".$Ticket->Id, + class => 'ticket-info-basics', + &> + <& /Ticket/Elements/ShowBasics, Ticket => $Ticket &> + </&> % if ($Ticket->CustomFields->First) { - <&| /Widgets/TitleBox, title => loc('Custom Fields'), - title_href => RT->Config->Get('WebPath')."/Ticket/Modify.html?id=".$Ticket->Id, - class => 'ticket-info-cfs' &> - <& /Ticket/Elements/ShowCustomFields, Ticket => $Ticket &> - </&> + <&| /Widgets/TitleBox, title => loc('Custom Fields'), + title_href => RT->Config->Get('WebPath')."/Ticket/Modify.html?id=".$Ticket->Id, + class => 'ticket-info-cfs', + &> + <& /Ticket/Elements/ShowCustomFields, Ticket => $Ticket &> + </&> % } - <&| /Widgets/TitleBox, title => loc('People'), - title_href => RT->Config->Get('WebPath')."/Ticket/ModifyPeople.html?id=".$Ticket->Id, - class => 'ticket-info-people' &> - <& /Ticket/Elements/ShowPeople, Ticket => $Ticket &> - </&> - <& /Ticket/Elements/ShowAttachments, Ticket => $Ticket, Attachments => $Attachments &> + <&| /Widgets/TitleBox, title => loc('People'), + title_href => RT->Config->Get('WebPath')."/Ticket/ModifyPeople.html?id=".$Ticket->Id, + class => 'ticket-info-people', + &> + <& /Ticket/Elements/ShowPeople, Ticket => $Ticket &> + </&> + + <& /Ticket/Elements/ShowAttachments, Ticket => $Ticket, Attachments => $Attachments &> - <& /Ticket/Elements/ShowRequestor, Ticket => $Ticket &> + <& /Ticket/Elements/ShowRequestor, Ticket => $Ticket &> % $m->callback( %ARGS, CallbackName => 'LeftColumn' ); - </td> - <td valign="top" class="boxcontainer"> + + </td> + <td valign="top" class="boxcontainer"> + +% $m->callback( %ARGS, CallbackName => 'RightColumnTop' ); + % if ( RT->Config->Get('EnableReminders') ) { - <&|/Widgets/TitleBox, title => loc("Reminders"), - title_href => RT->Config->Get('WebPath')."/Ticket/Reminders.html?id=".$Ticket->Id, - class => 'ticket-info-reminders' &> - <table> - <tr> - <td> + <&|/Widgets/TitleBox, title => loc("Reminders"), + title_href => RT->Config->Get('WebPath')."/Ticket/Reminders.html?id=".$Ticket->Id, + class => 'ticket-info-reminders', + &> + <table><tr><td> <form action="<%RT->Config->Get('WebPath')%>/Ticket/Display.html" method="post"> - <& /Ticket/Elements/Reminders, Ticket => $Ticket, ShowCompleted => 0 &> - <div align="right"><input type="submit" class="button" value="<&|/l&>Save</&>" /></div> + <& /Ticket/Elements/Reminders, Ticket => $Ticket, ShowCompleted => 0 &> + <div align="right"><input type="submit" class="button" value="<&|/l&>Save</&>" /></div> </form> - </td> - </tr> - </table> - </&> + </td></tr></table> + </&> % } - <&| /Widgets/TitleBox, title => loc("Dates"), - title_href => RT->Config->Get('WebPath')."/Ticket/ModifyDates.html?id=".$Ticket->Id, - class => 'ticket-info-dates' &> - <& /Ticket/Elements/ShowDates, Ticket => $Ticket &> - </&> + + <&| /Widgets/TitleBox, title => loc("Dates"), + title_href => RT->Config->Get('WebPath')."/Ticket/ModifyDates.html?id=".$Ticket->Id, + class => 'ticket-info-dates', + &> + <& /Ticket/Elements/ShowDates, Ticket => $Ticket &> + </&> + % my (@extra); % push @extra, titleright_raw => '<a href="'. RT->Config->Get('WebPath'). '/Ticket/Graphs/index.html?id='.$Ticket->id.'">'.loc('Graph').'</a>' unless RT->Config->Get('DisableGraphViz'); - <&| /Widgets/TitleBox, title => loc('Links'), - title_href => RT->Config->Get('WebPath')."/Ticket/ModifyLinks.html?id=".$Ticket->Id, - class => 'ticket-info-links', @extra &> - <& /Elements/ShowLinks, Ticket => $Ticket &> - </&> + <&| /Widgets/TitleBox, title => loc('Links'), + title_href => RT->Config->Get('WebPath')."/Ticket/ModifyLinks.html?id=".$Ticket->Id, + class => 'ticket-info-links', + @extra, + &> + <& /Elements/ShowLinks, Ticket => $Ticket &> + </&> + % $m->callback( %ARGS, CallbackName => 'RightColumn' ); - </td> - </tr> - </table> + </td> +</tr> +</table> <%ARGS> $Ticket => undef $Attachments => undef </%ARGS> - - - - diff --git a/rt/share/html/Ticket/Elements/ShowTransaction b/rt/share/html/Ticket/Elements/ShowTransaction index a533323a9..6ccbb0c89 100755 --- a/rt/share/html/Ticket/Elements/ShowTransaction +++ b/rt/share/html/Ticket/Elements/ShowTransaction @@ -55,11 +55,13 @@ <a name="txn-<% $Transaction->Id %>" href="<% $DisplayPath %>#txn-<% $Transaction->Id %>">#</a> <% $LastTransaction ? '<a id="lasttrans" name="lasttrans"></a>' : ''|n %> </span> +% $m->callback( Transaction => $Transaction, %ARGS, CallbackName => 'AfterAnchor' ); <span class="date"><% $transdate|n %></span> % my $desc = $Transaction->BriefDescription; % $m->callback( text => \$desc, Transaction => $Transaction, %ARGS, CallbackName => 'ModifyDisplay' ); <span class="description"> <& /Elements/ShowUser, User => $Transaction->CreatorObj &> - <% $TicketString %> <% $desc %> +% $m->callback( Transaction => $Transaction, %ARGS, CallbackName => 'AfterDescription' ); </span> % $m->callback( TimeTaken => \$TimeTaken, Transaction => $Transaction, %ARGS, CallbackName => 'ModifyTimeTaken' ); <span class="time-taken"><% $TimeTaken %></span> diff --git a/rt/share/html/Ticket/Elements/ShowTransactionAttachments b/rt/share/html/Ticket/Elements/ShowTransactionAttachments index 9c40b28da..a8cdfc11c 100644 --- a/rt/share/html/Ticket/Elements/ShowTransactionAttachments +++ b/rt/share/html/Ticket/Elements/ShowTransactionAttachments @@ -67,7 +67,10 @@ foreach my $message ( grep $_->__Value('Parent') == $Parent, @$Attachments ) { % if ( $DownloadableHeaders && !$message->Filename && $message->ContentType =~ /text/ ) { / <a href="<% $AttachPath %>/WithHeaders/<% $message->Id %>"><% loc('with headers') %></a> % } -<br /> + +% $m->callback(CallbackName => 'AfterDownloadLinks', ARGSRef => \%ARGS, Ticket => $Ticket, Transaction => $Transaction, Attachment => $message); + +<br /> <span class="downloadcontenttype"><% $message->ContentType %> <% $size_to_str->( $size ) %></span> </div> % } @@ -76,7 +79,7 @@ foreach my $message ( grep $_->__Value('Parent') == $Parent, @$Attachments ) { % if ( scalar ( grep $_->__Value('Parent') == $message->id, @$Attachments ) ) { <div class="messageattachments"> % } else { -<div class="messagebody <% RT->Config->Get('PlainTextMono', $session{'CurrentUser'}) ? ' plain-text-white-space' : ''%>"> +<div class="messagebody"> % } <%PERL> diff --git a/rt/share/html/Ticket/Elements/Tabs b/rt/share/html/Ticket/Elements/Tabs index 7deb8c18d..a9e697a9f 100755 --- a/rt/share/html/Ticket/Elements/Tabs +++ b/rt/share/html/Ticket/Elements/Tabs @@ -75,11 +75,13 @@ if ($Ticket) { # Don't display prev links if we're on the first ticket if ( $item_map->{ $Ticket->Id }->{prev} ) { - $searchtabs->{'_a'} = { - class => "nav", - path => "Ticket/Display.html?id=" . $item_map->{first}, - title => '<< ' . loc('First') - }; + if ( $item_map->{first} ) { + $searchtabs->{'_a'} = { + class => "nav", + path => "Ticket/Display.html?id=" . $item_map->{first}, + title => '<< ' . loc('First') + }; + } $searchtabs->{"_b"} = { class => "nav", path => "Ticket/Display.html?id=" @@ -96,11 +98,13 @@ if ($Ticket) { . $item_map->{ $Ticket->Id }->{next}, title => loc('Next') . ' >' }; - $searchtabs->{'e'} = { - class => "nav", - path => "Ticket/Display.html?id=" . $item_map->{last}, - title => loc('Last') . ' >>' - }; + if ( $item_map->{last} ) { + $searchtabs->{'e'} = { + class => "nav", + path => "Ticket/Display.html?id=" . $item_map->{last}, + title => loc('Last') . ' >>' + }; + } } } diff --git a/rt/share/html/Ticket/Elements/UpdateCc b/rt/share/html/Ticket/Elements/UpdateCc index 2538c82df..2559e5652 100644 --- a/rt/share/html/Ticket/Elements/UpdateCc +++ b/rt/share/html/Ticket/Elements/UpdateCc @@ -49,24 +49,32 @@ <input type="hidden" id="UpdateIgnoreAddressCheckboxes" name="UpdateIgnoreAddressCheckboxes" value="0"> <br /> -%foreach my $addr ( keys %txn_addresses) { -% next if ( grep {$addr eq $_} @req_addresses ); +%if (scalar @one_time_Ccs) { +<i class="label">(<&|/l&>check to add</&>)</i> +%} +%foreach my $addr ( @one_time_Ccs ) { <input id="UpdateCc-<%$addr%>" name="UpdateCc-<%$addr%>" type="checkbox" - onClick="checkboxToInput('UpdateCc', 'UpdateCc-<%$addr%>','<%$txn_addresses{$addr}->format%>' ); $(UpdateIgnoreAddressCheckboxes).value=1" +% my $clean_addr = $txn_addresses{$addr}->format; +% $clean_addr =~ s/'/\\'/g; + onClick="checkboxToInput('UpdateCc', 'UpdateCc-<%$addr%>','<%$clean_addr%>' ); $(UpdateIgnoreAddressCheckboxes).value=1" <% $ARGS{'UpdateCc-'.$addr} ? 'checked="checked"' : ''%> > <& /Elements/ShowUser, Address => $txn_addresses{$addr}&> %} </td></tr> <tr><td class="label"><&|/l&>One-time Bcc</&>:</td><td><& /Elements/EmailInput, Name => 'UpdateBcc', Size => '60', Default => $ARGS{UpdateBcc} &><br /> -%foreach my $addr ( keys %txn_addresses) { -% next if ( grep {$addr eq $_} @req_addresses ); +%if (scalar @one_time_Ccs) { +<i class="label">(<&|/l&>check to add</&>)</i> +%} +%foreach my $addr ( @one_time_Ccs ) { <input id="UpdateBcc-<%$addr%>" name="UpdateBcc-<%$addr%>" type="checkbox" - onClick="checkboxToInput('UpdateBcc', 'UpdateBcc-<%$addr%>','<%$txn_addresses{$addr}->format%>' ); $(UpdateIgnoreAddressCheckboxes).value=1" +% my $clean_addr = $txn_addresses{$addr}->format; +% $clean_addr =~ s/'/\\'/g; + onClick="checkboxToInput('UpdateBcc', 'UpdateBcc-<%$addr%>','<%$clean_addr%>' ); $(UpdateIgnoreAddressCheckboxes).value=1" <% $ARGS{'UpdateBcc-'.$addr} ? 'checked="checked"' : ''%>> <& /Elements/ShowUser, Address => $txn_addresses{$addr}&> %} @@ -77,4 +85,10 @@ $TicketObj <%init> my %txn_addresses = %{$TicketObj->TransactionAddresses}; my @req_addresses = split /,/, $TicketObj->RequestorAddresses; +my @one_time_Ccs; + +foreach my $addr ( keys %txn_addresses) { + next if ( grep {$addr eq $_} @req_addresses ); + push @one_time_Ccs,$addr; +} </%init> diff --git a/rt/share/html/Ticket/ModifyAll.html b/rt/share/html/Ticket/ModifyAll.html index 762870099..41eda1b97 100755 --- a/rt/share/html/Ticket/ModifyAll.html +++ b/rt/share/html/Ticket/ModifyAll.html @@ -97,6 +97,7 @@ <option value="response"><&|/l&>Reply to requestors</&></option> % } </select> +% $m->callback( %ARGS, CallbackName => 'AfterUpdateType' ); </td> </tr> <tr> @@ -133,8 +134,13 @@ </tr> <tr> <td class="labeltop"><&|/l&>Content</&>:</td> - <td class="entry"><& /Elements/MessageBox, Name=>"UpdateContent", QuoteTransaction=>$ARGS{QuoteTransaction} &></td> - </tr> + <td class="entry"> +% if (exists $ARGS{UpdateContent}) { + <& /Elements/MessageBox, Name=>"UpdateContent", Default=>$ARGS{UpdateContent}, IncludeSignature => 0 &> +% } else { + <& /Elements/MessageBox, Name=>"UpdateContent", QuoteTransaction=>$ARGS{QuoteTransaction} &> +% } + </td></tr> </table> </&> diff --git a/rt/share/html/Ticket/ModifyDates.html b/rt/share/html/Ticket/ModifyDates.html index 69bfde8ef..22bac10cb 100755 --- a/rt/share/html/Ticket/ModifyDates.html +++ b/rt/share/html/Ticket/ModifyDates.html @@ -69,6 +69,7 @@ my $TicketObj = LoadTicket($id); $m->callback( TicketObj => $TicketObj, ARGSRef => \%ARGS ); my @results = ProcessTicketDates( TicketObj => $TicketObj, ARGSRef => \%ARGS); +push @results, ProcessObjectCustomFieldUpdates(Object => $TicketObj, ARGSRef => \%ARGS); $TicketObj->ApplyTransactionBatch; </%INIT> diff --git a/rt/share/html/Ticket/Update.html b/rt/share/html/Ticket/Update.html index d3c2a09c4..f5cdddea8 100755 --- a/rt/share/html/Ticket/Update.html +++ b/rt/share/html/Ticket/Update.html @@ -55,7 +55,7 @@ <form action="Update.html" name="TicketUpdate" method="post" enctype="multipart/form-data"> -% $m->callback( CallbackName => 'FormStart', ARGSRef => \%ARGS, Ticket => $TicketObj ); +% $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}||'' %>" /> @@ -97,8 +97,11 @@ <option value="response" <% ($ARGS{'UpdateType'} && $ARGS{'UpdateType'} eq "response") ? qq[ selected="selected"] : !$ARGS{'UpdateType'}&&$ResponseDefault |n %>><&|/l&>Reply to requestors</&></option> % } </select> +% $m->callback( %ARGS, CallbackName => 'AfterUpdateType' ); +</td></tr> +<tr><td class="label"><&|/l&>Subject</&>:</td><td> <input name="UpdateSubject" size="60" value="<% $ARGS{UpdateSubject} || $TicketObj->Subject()%>" /> +% $m->callback( %ARGS, CallbackName => 'AfterSubject' ); </td></tr> -<tr><td class="label"><&|/l&>Subject</&>:</td><td> <input name="UpdateSubject" size="60" value="<% $ARGS{UpdateSubject} || $TicketObj->Subject()%>" /></td></tr> <& /Ticket/Elements/UpdateCc, %ARGS, TicketObj => $TicketObj &> @@ -126,6 +129,7 @@ &> </td></tr> % } +% $m->callback( %ARGS, CallbackName => 'AfterGnuPG' ); <tr><td class="label" valign="top"><&|/l&>Message</&>:</td><td> % $m->callback( %ARGS, CallbackName => 'BeforeMessageBox' ); @@ -136,7 +140,9 @@ <& /Elements/MessageBox, Name=>"UpdateContent", Default=>$ARGS{UpdateContent}, IncludeSignature => 0, %ARGS&> % $ARGS{'QuoteTransaction'} = $temp; % } else { -<& /Elements/MessageBox, Name=>"UpdateContent", %ARGS &> +% my $IncludeSignature = 1; +% $IncludeSignature = 0 if $Action ne 'Respond' && !RT->Config->Get('MessageBoxIncludeSignatureOnComment'); +<& /Elements/MessageBox, Name=>"UpdateContent", IncludeSignature => $IncludeSignature, %ARGS &> % } </td></tr> </table> @@ -256,6 +262,22 @@ if ( $ARGS{'SubmitTicket'} ) { $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; + } +} + if ( !$checks_failure && exists $ARGS{SubmitTicket} ) { $m->callback( Ticket => $TicketObj, ARGSRef => \%ARGS, CallbackName => 'BeforeDisplay' ); return $m->comp('Display.html', TicketObj => $TicketObj, %ARGS); diff --git a/rt/share/html/Tools/Reports/CreatedByDates.html b/rt/share/html/Tools/Reports/CreatedByDates.html index 9ca69557e..ce075970b 100644 --- a/rt/share/html/Tools/Reports/CreatedByDates.html +++ b/rt/share/html/Tools/Reports/CreatedByDates.html @@ -76,8 +76,8 @@ $q->LoadByCols(Name => $Queue); % if ($Queue|| $CreatedBefore ||$CreatedAfter) { % # if we have a queue, do the search % if ($Queue) { $query .= " AND Queue = '$Queue'"} -% if ($CreatedBefore) { $query .= " AND Created < '".$before->ISO."'"; } -% if ($CreatedAfter) { $query .= " AND Created > '".$after->ISO."'"} +% if ($CreatedBefore) { $query .= " AND Created < '".$before->ISO(Timezone => 'user') ."'"; } +% if ($CreatedAfter) { $query .= " AND Created > '".$after->ISO(Timezone => 'user')."'"} % my $groupby = 'Status'; <& /Search/Elements/Chart, Query => $query, PrimaryGroupBy => $groupby &> % } @@ -86,9 +86,9 @@ $q->LoadByCols(Name => $Queue); <br /><&|/l&>Queue</&>: <& /Elements/SelectQueue, Name => 'Queue', NamedValues => 1, Default => $q->id &> <br /><&|/l&>Tickets created after</&>: -<& /Elements/SelectDate, Name => 'CreatedAfter', Default => ($CreatedAfter) ? $after->ISO : ''&> +<& /Elements/SelectDate, Name => 'CreatedAfter', Default => ($CreatedAfter) ? $after->ISO(Timezone => 'user') : ''&> <br /><&|/l&>Tickets created before</&>: -<& /Elements/SelectDate, Name => 'CreatedBefore', Default => ($CreatedBefore) ? $before->ISO : ''&> +<& /Elements/SelectDate, Name => 'CreatedBefore', Default => ($CreatedBefore) ? $before->ISO(Timezone => 'user') : ''&> <& /Elements/Submit&> </form> diff --git a/rt/share/html/Tools/Reports/ResolvedByDates.html b/rt/share/html/Tools/Reports/ResolvedByDates.html index 455eaedd2..48a952682 100644 --- a/rt/share/html/Tools/Reports/ResolvedByDates.html +++ b/rt/share/html/Tools/Reports/ResolvedByDates.html @@ -77,8 +77,8 @@ $q->LoadByCols(Name => $Queue); % # if we have a queue, do the search % $query = "Status = 'resolved'"; % if ($Queue) { $query .= " AND Queue = '$Queue'"} -% if ($ResolvedBefore) { $query .= " AND Resolved < '".$before->ISO."'"; } -% if ($ResolvedAfter) { $query .= " AND Resolved > '".$after->ISO."'"} +% if ($ResolvedBefore) { $query .= " AND Resolved < '".$before->ISO(Timezone => 'user')."'"; } +% if ($ResolvedAfter) { $query .= " AND Resolved > '".$after->ISO(Timezone => 'user')."'"} % my $groupby = 'Owner'; <& /Search/Elements/Chart, Query => $query, PrimaryGroupBy => $groupby &> % } @@ -87,9 +87,9 @@ $q->LoadByCols(Name => $Queue); <br /><&|/l&>Queue</&>: <& /Elements/SelectQueue, Name => 'Queue', NamedValues => 1, Default => $q->id &> <br /><&|/l&>Tickets resolved after</&>: -<& /Elements/SelectDate, Name => 'ResolvedAfter', Default => ($ResolvedAfter) ? $after->ISO : ''&> +<& /Elements/SelectDate, Name => 'ResolvedAfter', Default => ($ResolvedAfter) ? $after->ISO(Timezone => 'user') : ''&> <br /><&|/l&>Tickets resolved before</&>: -<& /Elements/SelectDate, Name => 'ResolvedBefore', Default => ($ResolvedBefore) ? $before->ISO : ''&> +<& /Elements/SelectDate, Name => 'ResolvedBefore', Default => ($ResolvedBefore) ? $before->ISO(Timezone => 'user') : ''&> <& /Elements/Submit&> </form> diff --git a/rt/share/html/User/Elements/Tabs b/rt/share/html/User/Elements/Tabs index 48cf1808b..7f9aca4dd 100755 --- a/rt/share/html/User/Elements/Tabs +++ b/rt/share/html/User/Elements/Tabs @@ -52,41 +52,43 @@ Title => $Title &> <%INIT> - my $tabs = { - - a => { title => loc('Settings'), - path => 'Prefs/Other.html', - }, - - b => { title => loc('About me'), - path => 'User/Prefs.html', - }, - g => { title => loc('Personal Groups'), - path => 'User/Groups/', - }, - h => { title => loc('Delegation'), - path => 'User/Delegation.html', - }, - f => { title => loc('Search options'), - path => 'Prefs/SearchOptions.html', - }, - r => { title => loc('RT at a glance'), - path => 'Prefs/MyRT.html', - }, - }; +my $tabs = { + a => { + title => loc('Settings'), + path => 'Prefs/Other.html', + }, + b => { + title => loc('About me'), + path => 'User/Prefs.html', + }, + g => { + title => loc('Personal Groups'), + path => 'User/Groups/', + }, + h => { + title => loc('Delegation'), + path => 'User/Delegation.html', + }, + f => { + title => loc('Search options'), + path => 'Prefs/SearchOptions.html', + }, + r => { + title => loc('RT at a glance'), + path => 'Prefs/MyRT.html', + }, +}; - # Now let callbacks add their extra tabs - $m->callback( %ARGS, tabs => $tabs ); - - foreach my $tab (sort keys %{$tabs}) { - if ($tabs->{$tab}->{'path'} eq $current_tab) { - $tabs->{$tab}->{"subtabs"} = $subtabs; - $tabs->{$tab}->{"current_subtab"} = $current_subtab; - } - } -</%INIT> +# Now let callbacks add their extra tabs +$m->callback( %ARGS, tabs => $tabs ); +foreach my $tab (values %$tabs) { + next unless $tab->{'path'} eq $current_tab; + $tab->{"subtabs"} = $subtabs; + $tab->{"current_subtab"} = $current_subtab; +} +</%INIT> <%ARGS> $subtabs => undef $current_tab => undef diff --git a/rt/share/html/User/Prefs.html b/rt/share/html/User/Prefs.html index f52fdcbdf..884cf85e4 100755 --- a/rt/share/html/User/Prefs.html +++ b/rt/share/html/User/Prefs.html @@ -107,27 +107,13 @@ % $m->callback( %ARGS, UserObj => $UserObj, CallbackName => 'FormLeftColumn' ); </td> <td valign="top" class="boxcontainer"> -% unless (RT->Config->Get('WebExternalAuth') and !RT->Config->Get('WebFallbackToInternalAuth')) { + <&| /Widgets/TitleBox, title => loc('Password'), id => "user-prefs-password" &> -<table> -<tr> -<td class="label"> -<&|/l&>New Password</&>: -</td> -<td class="value"> -<input type="password" name="Pass1" autocomplete="off"/> -</td> -</tr> -<tr><td class="label"> -<&|/l&>Retype Password</&>: -</td> -<td class="value"> -<input type="password" name="Pass2" autocomplete="off" /> -</td> -</tr> -</table> +<& /Elements/EditPassword, + User => $UserObj, + Name => [qw(CurrentPass Pass1 Pass2)], +&> </&> -% } <&| /Widgets/TitleBox, title => loc('Location'), id => "user-prefs-location" &> <table cellspacing="0" cellpadding="0"> @@ -221,6 +207,7 @@ unless ( $UserObj->id ) { if $Name; Abort(loc("Couldn't load user")); } +$id = $UserObj->id; my @results; @@ -259,13 +246,14 @@ if ( $SetPrivileged and $Privileged != $UserObj->Privileged ) { push @results, loc('Privileged status: [_1]', loc_fuzzy($msg)); } -#TODO: make this report errors properly -if ( defined $Pass1 and length $Pass1 and $Pass1 eq $Pass2 and !$UserObj->IsPassword($Pass1) ) { - my ($code, $msg); - ($code, $msg) = $UserObj->SetPassword($Pass1); - push @results, loc('Password: [_1]', loc_fuzzy($msg)); -} elsif ( defined $Pass1 && length $Pass1 && $Pass1 ne $Pass2 ) { - push @results, loc("Passwords do not match. Your password has not been changed"); +my %password_cond = $UserObj->CurrentUserRequireToSetPassword; +if (defined $Pass1 && length $Pass1 ) { + my ($status, $msg) = $UserObj->SafeSetPassword( + Current => $CurrentPass, + New => $Pass1, + Confirmation => $Pass2, + ); + push @results, loc("Password: [_1]", $msg); } if ( $ARGS{'ResetAuthToken'} ) { @@ -308,7 +296,8 @@ $City => undef $State => undef $Zip => undef $Country => undef +$CurrentPass => undef $Pass1 => undef -$Pass2=> undef +$Pass2 => undef $Create=> undef </%ARGS> diff --git a/rt/share/html/Widgets/Form/Select b/rt/share/html/Widgets/Form/Select index e77861740..4587f1d58 100644 --- a/rt/share/html/Widgets/Form/Select +++ b/rt/share/html/Widgets/Form/Select @@ -117,7 +117,10 @@ if ( $ValuesCallback ) { } } unless (defined $DefaultLabel ) { - $DefaultLabel = loc('Use system default ([_1])', join ', ', map{ loc($ValuesLabel{$_} || $_) } @DefaultValue); + $DefaultLabel = loc('Use system default ([_1])', + join ', ', map loc($ValuesLabel{$_} || $_), grep defined, + @DefaultValue + ); } </%INIT> </%METHOD> |