[Rt-commit] rt branch 5.0/add-article-portlet created. rt-5.0.3-129-ge6aa0f7fcd

BPS Git Server git at git.bestpractical.com
Tue Oct 11 15:03:52 UTC 2022


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "rt".

The branch, 5.0/add-article-portlet has been created
        at  e6aa0f7fcddf01d01dfa1ed3e393d1e15fac4240 (commit)

- Log -----------------------------------------------------------------
commit e6aa0f7fcddf01d01dfa1ed3e393d1e15fac4240
Author: Brian Conry <bconry at bestpractical.com>
Date:   Mon Jul 18 08:48:58 2022 -0500

    Update /SelfService/Article/Display.html to new API
    
    This change converts /SelfService/Article/Display.html, and
    /Elements/ShowArticleCustomFields, which is currently only used by
    SelfService, to use the new helper API on RT::Article instead of
    querying all of the attributes of the Class directly.

diff --git a/share/html/Elements/ShowArticleCustomFields b/share/html/Elements/ShowArticleCustomFields
index 253ededef1..76858dd169 100644
--- a/share/html/Elements/ShowArticleCustomFields
+++ b/share/html/Elements/ShowArticleCustomFields
@@ -49,6 +49,7 @@
 %               ARGSRef => \%ARGS, CustomFields => $CustomFields);
 <div>
 % while ( my $CustomField = $CustomFields->Next ) {
+% next unless $Object->IncludeCFValue($CustomField);
 % my $Values = $Object->CustomFieldValues( $CustomField->Id );
 % my $count = $Values->Count;
 % next if $HideEmpty and not $count;
@@ -65,12 +66,13 @@
 % $m->callback( CallbackName => 'ModifyFieldClasses', CustomField => $CustomField,
 %               Object => $Object, Classes => \@classes );
   <div class="form-row <% join(' ', @classes) %>" id="CF-<%$CustomField->id%>-ShowRow">
-% if ($HideFieldNames->{$CustomField->id}) {
+% if ($HideFieldNames->{$CustomField->id} || ! $Object->IncludeCFTitle($CustomField)) {
     <div class="value col-12 <% $count ? '' : ' no-value' %>">
 %} else {
     <div class="label col-3"><% $CustomField->Name %>:</div>
     <div class="value col-9 <% $count ? '' : ' no-value' %>">
 % }
+% if ($Object->IncludeCFValue($CustomField)) {
       <span class="current-value">
 % unless ( $count ) {
 <&|/l&>(no value)</&>
@@ -86,6 +88,7 @@
 </ul>
 % }
       </span>
+% }
     </div>
 % $m->callback( CallbackName => 'AfterCustomFieldValue', CustomField => $CustomField,
 %               Object => $Object );
diff --git a/share/html/SelfService/Article/Display.html b/share/html/SelfService/Article/Display.html
index 6b94b950f6..af3ff52926 100644
--- a/share/html/SelfService/Article/Display.html
+++ b/share/html/SelfService/Article/Display.html
@@ -48,9 +48,9 @@
 <& /SelfService/Elements/Header, Title => $article->Name &>
 <div id="article-display-container" class="mx-auto max-width-md">
 % my $title = "";
-% $title = $article->Summary if $include{Summary};
+% $title = $article->Summary if $article->IncludeSummary;
 <&| /Widgets/TitleBox, title => $title, class => 'article-display-simple', content_class => 'mx-auto width-md' &>
-<& /Elements/ShowArticleCustomFields, Object => $article, CustomFields => $custom_fields, HideFieldNames => \%hide_field_names &>
+<& /Elements/ShowArticleCustomFields, Object => $article, CustomFields => $custom_fields &>
 </&>
 </div>
 <%init>
@@ -70,35 +70,7 @@ unless ( $article->CurrentUserHasRight('ShowArticle') ) {
 $id = $article->id;
 my $class = $article->ClassObj;
 
-# Build up the hash of things to include/exclude, as well
-# as the array of custom field IDs to limit by
-my %include = (Name => 1, Summary => 1, EscapeHTML => 1);
-my @exclude_cf_ids;
-my %hide_field_names;
-
-my $cfs = $article->CustomFields;
-while ( my $cf = $cfs->Next ) {
-    $include{"CF-Title-" . $cf->Id} = 1;
-    $include{"CF-Value-" . $cf->Id} = 1;
-}
-
-# Load show/hide settings from class configuration
-foreach my $key ( keys %include ) {
-    $include{$key} = not $class->FirstAttribute("Skip-$key");
-    if ($key =~ /^CF-Value-(\d+)$/ && !$include{$key}) {
-        push(@exclude_cf_ids, $1);
-    }
-    if ($key =~ /^CF-Title-(\d+)$/ && !$include{$key}) {
-        $hide_field_names{$1} = 1;
-    }
-}
-
-my $custom_fields = $article->CustomFields;
-if ( scalar(@exclude_cf_ids) ) {
-    $custom_fields->Limit( FIELD    => 'id',
-                           OPERATOR => 'NOT IN',
-                           VALUE    => \@exclude_cf_ids );
-}
+my $custom_fields = $article->IncludedCustomFields;
 
 </%init>
 <%args>

commit 2a5de2fd8d9837dacbd637160c7ad52ba5e00479
Author: Brian Conry <bconry at bestpractical.com>
Date:   Fri Jul 15 15:08:19 2022 -0500

    Convert Article Element "Preformatted" to use new API
    
    This change converts /Articles/Article/Elements/Preformatted, which is
    used when including article text in a message on a ticket, to use the
    new helper API on RT::Article instead of querying all of the attributes
    of the Class directly.

diff --git a/share/html/Articles/Article/Elements/Preformatted b/share/html/Articles/Article/Elements/Preformatted
index 36b12eb339..2af3129f91 100644
--- a/share/html/Articles/Article/Elements/Preformatted
+++ b/share/html/Articles/Article/Elements/Preformatted
@@ -45,54 +45,45 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-% if ($include{Name}) {
+% if ($Article->IncludeName) {
 #<%$Article->Id%>: <%$Article->Name || loc('(no name)')%>
 <%'-' x length("#".$Article->Id.": ".($Article->Name || loc('(no name)'))) %>
 % }
-% if ( $include{Summary} && ($Article->Summary||'') =~ /\S/ ) {
+% if ( $Article->IncludeSummary && ($Article->Summary||'') =~ /\S/ ) {
 <% $Article->Summary %>
 % }
 % while (my $cf = $cfs->Next) {
-%   next unless $include{"CF-Title-".$cf->Id} or $include{"CF-Value-".$cf->Id};
 %   my $values = $Article->CustomFieldValues($cf->Id);
 %   if ($values->Count == 1) {
 %     my $value = $values->First; 
-%     if ($include{"CF-Title-".$cf->Id}) {
+%     if ($Article->IncludeCFTitle($cf)) {
 <%      $cf->Name%>:
 <%      '-' x length($cf->Name) %>
 %     }
-%     if ($value && $include{"CF-Value-".$cf->Id}) {
+%     if ($value && $Article->IncludeCFValue($cf)) {
 <%      $get_content->( $value ) %>
 %     }
 %   } else {
 %     my $val = $values->Next;
-%     if ($include{"CF-Title-".$cf->Id}) {
+%     if ($Article->IncludeCFTitle($cf)) {
 <%      $cf->Name%>: \
 %     }
-%     if ($val && $include{"CF-Value-".$cf->Id}) {
+%     if ($val && $Article->IncludeCFValue($cf)) {
 <%      $get_content->( $val ) %>
 %     }
 %     while ($val = $values->Next) { 
-%       if ($include{"CF-Title-".$cf->Id}) {
+%       if ($Article->IncludeCFTitle($cf)) {
 <%        ' ' x length($cf->Name)%>  \
 %       }
-%       if ($include{"CF-Value-".$cf->Id}) {
+%       if ($Article->IncludeCFValue($cf)) {
 <%        $get_content->( $val ) %>
 %       }
 %     } 
 %   }
 % }
 <%init>
-my $class = $Article->ClassObj;
-my %include = (Name => 1, Summary => 1, EscapeHTML => 1);
-my $cfs = $class->ArticleCustomFields;
-while ( my $cf = $cfs->Next ) {
-    $include{"CF-Title-" . $cf->Id} = 1;
-    $include{"CF-Value-" . $cf->Id} = 1;
-}
-foreach my $key ( keys %include ) {
-    $include{$key} = not $class->FirstAttribute("Skip-$key");
-}
+my $do_escape = $Article->DoEscapeHTML;
+my $cfs = $Article->IncludedCustomFields;
 
 my $get_content = sub {
     my $value = shift;
@@ -107,7 +98,7 @@ my $get_content = sub {
         content => \$content,
     );
 
-    if ( $include{'EscapeHTML'} && $content =~ /<.{1,5}>/ ) {
+    if ( $do_escape && $content =~ /<.{1,5}>/ ) {
         $content = RT::Interface::Email::ConvertHTMLToText( $content );
     }
     return $content;

commit ce041090e5dfa0ca50242e1a396e59f4cf9c2c39
Author: Brian Conry <bconry at bestpractical.com>
Date:   Tue Jul 5 16:15:54 2022 -0500

    Add portlet for displaying article content
    
    This commit adds a portlet for displaying article content,
    /Articles/Article/Elements/InlineDisplay.   This is similar to the one
    that prepares an article for inclusion in a reply, but instead of
    converting the content for addition to an editor, it prepares it for
    display as part of the current page.

diff --git a/share/html/Articles/Article/Elements/InlineDisplay b/share/html/Articles/Article/Elements/InlineDisplay
new file mode 100644
index 0000000000..c81000dfdb
--- /dev/null
+++ b/share/html/Articles/Article/Elements/InlineDisplay
@@ -0,0 +1,105 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2022 Best Practical Solutions, LLC
+%#                                          <sales at 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 }}}
+
+  <div class="form-row">
+    <div class="label col-3">
+% if ($Article->IncludeName) {
+    #<% $Article->Id %>: <% $Article->Name || loc('(no name)') %>
+% }
+    </div>
+    <div class="label col-9 text-left">
+% if ( $Article->IncludeSummary && ($Article->Summary||'') =~ /\S/ ) {
+    <% $Article->Summary %>
+% }
+    </div>
+  </div>
+% while (my $cf = $cfs->Next) {
+    <div class="form-row">
+%   my $values = $Article->CustomFieldValues($cf->Id);
+%   my $first_value = 1;
+%   while (my $val = $values->Next) {
+      <div class="label col-3">
+%     if ($first_value && $Article->IncludeCFTitle($cf)) {
+        <% $cf->Name %>:
+%     }
+%     else {
+%     }
+      </div>
+      <div class="value col-9">
+%     if ($val && $Article->IncludeCFValue($cf)) {
+        <% $get_content->( $val ) |n%>
+%     }
+%     $first_value = 0;
+      </div>
+%   }
+    </div>
+% }
+  <hr class="clear">
+
+<%init>
+my $do_escape = $Article->DoEscapeHTML;
+my $cfs = $Article->IncludedCustomFields;
+
+my $get_content = sub {
+    my $value = shift;
+    return '' unless $value;
+
+    my $content = $value->Content;
+    return '' unless defined $content && length $content;
+
+    if ( $do_escape && $content =~ /<.{1,5}>/ ) {
+        $content = $m->interp->apply_escapes( $content, 'h' )
+    }
+
+    return $content;
+};
+
+</%init>
+<%args>
+$Article
+</%args>
diff --git a/share/html/Elements/ArticleContentAsPortlet b/share/html/Elements/ArticleContentAsPortlet
new file mode 100644
index 0000000000..180ab3ec1e
--- /dev/null
+++ b/share/html/Elements/ArticleContentAsPortlet
@@ -0,0 +1,81 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2022 Best Practical Solutions, LLC
+%#                                          <sales at 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 }}}
+<&|/Widgets/TitleBox, title => loc($PortletTitle), class => $TitleClass &>
+
+% if ($ContentClass) {
+<div class="<% $ContentClass %>">
+% }
+% if ( $ArticleObj and $ArticleObj->Id ) {
+    <& /Articles/Article/Elements/InlineDisplay, Article => $ArticleObj &>
+% }
+% elsif( $ContentIfEmpty ) {
+    <% $ContentIfEmpty %>
+% }
+% if ($ContentClass) {
+</div>
+% }
+
+</&>
+<%init>
+$ArticleObj ||= RT::Article->new( $session{CurrentUser} );
+
+unless ( $ArticleObj->CurrentUserHasRight('ShowArticle') ) {
+    $ArticleObj->Load(0);
+}
+
+my $ArticleId = $ArticleObj->Id || '';
+$PortletTitle ||= $ArticleObj->ClassObj->Name;
+
+</%init>
+<%ARGS>
+$ArticleObj => undef
+$ContentClass => ''
+$TitleClass => 'article-content'
+$ContentIfEmpty => loc("Article not avialable")
+$PortletTitle => undef
+</%ARGS>

commit 5e653bdf74c1ce0e6d985ce79d8e759688702923
Author: Brian Conry <bconry at bestpractical.com>
Date:   Fri Jul 15 14:55:56 2022 -0500

    Add pass-through methods for class-level display flags
    
    This change adds a set of convenience pass-through methods for querying
    the class-level flags that control how the article should be displayed.

diff --git a/lib/RT/Article.pm b/lib/RT/Article.pm
index 590b4fb989..6aa42a43bf 100644
--- a/lib/RT/Article.pm
+++ b/lib/RT/Article.pm
@@ -581,6 +581,44 @@ sub CustomFieldLookupType {
     "RT::Class-RT::Article";
 }
 
+sub IncludedCustomFields {
+    my $self = shift;
+
+    my $cfs = $self->ClassObj->IncludedArticleCustomFields;
+
+    $cfs->SetContextObject( $self );
+
+    return $cfs;
+}
+
+sub IncludeName {
+    my $self = shift;
+    return $self->ClassObj->IncludeName;
+}
+
+sub IncludeSummary {
+    my $self = shift;
+    return $self->ClassObj->IncludeSummary;
+}
+
+sub DoEscapeHTML {
+    my $self = shift;
+    return $self->ClassObj->DoEscapeHTML;
+}
+
+sub IncludeCFTitle {
+    my $self = shift;
+    my $cfobj = shift;
+
+    return $self->ClassObj->IncludeArticleCFTitle( $cfobj );
+}
+
+sub IncludeCFValue {
+    my $self = shift;
+    my $cfobj = shift;
+
+    return $self->ClassObj->IncludeArticleCFValue( $cfobj );
+}
 
 sub ACLEquivalenceObjects {
     my $self = shift;

commit f258071350ba3af9b8bf9ffd6f88e171656a3e7f
Author: Brian Conry <bconry at bestpractical.com>
Date:   Fri Jul 15 14:48:22 2022 -0500

    Add helper methods on Class for displaying articles
    
    This change adds helper methods to RT::Class to assist in displaying an
    article.
    
    These methods provide a way to query the display configuration of the
    class without having to check the attributes directly.  This covers the
    display of the article name and summary, whether or not to EscapeHTML
    on custom field values, which custom fields should be included, and
    which custom fields should have their name displayed.
    
    Also provides a convenience method to get an RT::CustomFields collection
    object that is pre-filtered according to these display flags.

diff --git a/lib/RT/Class.pm b/lib/RT/Class.pm
index 236d8548d9..1c04a880b2 100644
--- a/lib/RT/Class.pm
+++ b/lib/RT/Class.pm
@@ -70,6 +70,8 @@ sub Table {'Classes'}
 use RT::CustomField;
 RT::CustomField->RegisterLookupType( CustomFieldLookupType() => 'Classes' );    #loc
 
+=head1 METHODS
+
 =head2 Load IDENTIFIER
 
 Loads a class, either by name or by id
@@ -202,7 +204,7 @@ sub ArticleCustomFields {
 }
 
 
-=head1 AppliedTo
+=head2 AppliedTo
 
 Returns collection of Queues this Class is applied to.
 Doesn't takes into account if object is applied globally.
@@ -225,7 +227,7 @@ sub AppliedTo {
     return $res;
 }
 
-=head1 NotAppliedTo
+=head2 NotAppliedTo
 
 Returns collection of Queues this Class is not applied to.
 
@@ -396,6 +398,112 @@ sub SetSubjectOverride {
     }
 }
 
+=head2 IncludeName
+
+Returns 1 if the class is configured for the class Name to
+be included with article content and '' otherwise.
+
+=cut
+
+sub IncludeName {
+    my $self = shift;
+    return not $self->FirstAttribute('Skip-Name');
+}
+
+=head2 IncludeSummary
+
+Returns 1 if the class is configured for the class Summary to
+be included with article content and '' otherwise.
+
+=cut
+
+sub IncludeSummary {
+    my $self = shift;
+    return not $self->FirstAttribute('Skip-Summary');
+}
+
+=head2 DoEscapeHTML
+
+Returns 1 if the content of custom fields should be filtered
+through EscapeHTML and '' otherwise.
+
+=cut
+
+sub DoEscapeHTML {
+    my $self = shift;
+    return not $self->FirstAttribute('Skip-EscapeHTML');
+}
+
+sub _BuildCFInclusionData {
+    my $self = shift;
+
+    my $include = $self->{'_cf_include_hash'} = {};
+    my $excludes = $self->{'_cf_exclude_list'} = [];
+
+    my $cfs = $self->ArticleCustomFields;
+
+    while ( my $cf = $cfs->Next ) {
+        my $cfid = $cf->Id;
+        $include->{"Title-$cfid"} = not $self->FirstAttribute("Skip-CF-Title-$cfid");
+        $include->{"Value-$cfid"} = not $self->FirstAttribute("Skip-CF-Value-$cfid");
+        push @$excludes, $cfid unless $include->{"Title-$cfid"} or $include->{"Value-$cfid"};
+    }
+}
+
+=head2 IncludedArticleCustomFields
+
+As ArticleCustomFields, but filtered to only include those
+that should have either their Title (Name) or Value included
+in content.
+
+=cut
+
+sub IncludedArticleCustomFields {
+    my $self = shift;
+
+    $self->_BuildCFInclusionData;
+
+    my $cfs = $self->ArticleCustomFields;
+
+    if ( @{ $self->{'_cf_exclude_list'} } ) {
+        $cfs->Limit( FIELD => 'id', OPERATOR => 'NOT IN', VALUE => $self->{'_cf_exclude_list'} );
+    }
+
+    return $cfs;
+}
+
+=head2 IncludeArticleCFTitle CustomFieldObject
+
+Returns true if the title of the custom field should
+be included in article content, and false otherwise.
+
+=cut
+
+sub IncludeArticleCFTitle {
+    my $self = shift;
+    my $cfobj = shift;
+
+    $self->_BuildCFInclusionData unless $self->{'_cf_include_hash'};
+
+    return $self->{'_cf_include_hash'}{"Title-".$cfobj->Id};
+}
+
+=head2 IncludeArticleCFValue CustomFieldObject
+
+Returns true if the value of the custom field should
+be included in article content, and false otherwise.
+
+=cut
+
+sub IncludeArticleCFValue {
+    my $self = shift;
+    my $cfobj = shift;
+
+    $self->_BuildCFInclusionData unless $self->{'_cf_include_hash'};
+
+    return $self->{'_cf_include_hash'}{"Value-".$cfobj->Id};
+}
+
 =head2 id
 
 Returns the current value of id. 

-----------------------------------------------------------------------


hooks/post-receive
-- 
rt


More information about the rt-commit mailing list