[Rt-commit] rtir branch, 4.2/rss-feed-reader, repushed

Aaron Trevena ast at bestpractical.com
Tue Jun 2 06:55:57 EDT 2020


The branch 4.2/rss-feed-reader was deleted and repushed:
       was ed6039631bb382ff4ed0910790f35f2c610926c3
       now be35374d8a51ab565e5a444aca4b7890b3252f39

1: 4652c318 ! 1: be35374d Added external feeds to tools to create incidents from RSS
    @@ -1,4 +1,4 @@
    -Author: Aaron Trevena <aaron at aarontrevena.co.uk>
    +Author: Aaron Trevena <ast at bestpractical.com>
     
         Added external feeds to tools to create incidents from RSS
         
    @@ -20,6 +20,47 @@
      build_requires('Test::More');
      build_requires('File::Find');
     
    +diff --git a/etc/RTIR_Config.pm b/etc/RTIR_Config.pm
    +--- a/etc/RTIR_Config.pm
    ++++ b/etc/RTIR_Config.pm
    +@@
    + 
    + Set($RunWhoisRequestByDefault, 0);
    + 
    ++=item %ExternalFeeds
    ++
    ++Sources for the External Feeds tool, currently RSS is supported. Provide a Name and URI for each source and you can also provide an optional Description.
    ++
    ++
    ++Set( %ExternalFeeds, (
    ++    'RSS' => [
    ++        { Name => 'US Cert Alerts', URI => 'https://www.us-cert.gov/ncas/alerts.xml', Description => 'US Cert Alerts' },
    ++     ....
    ++     ]
    ++  )
    ++);
    ++
    ++The initial list is US Cert Alerts, UK NCSC Security News, Security Focus Vulnerability Alerts, Threatpost Vulnerability Alerts and Bugtraq.
    ++
    ++=cut
    ++
    ++Set( %ExternalFeeds, (
    ++    'RSS' => [
    ++        { Name => 'US Cert Alerts', URI => 'https://www.us-cert.gov/ncas/alerts.xml', Description => 'US Cert Alerts' },
    ++        { Name => 'UK NCSC Security News', URI => 'https://www.ncsc.gov.uk/api/1/services/v1/all-rss-feed.xml', Description => 'UK NCSC Security News' },
    ++        { Name => 'Security Focus Vulnerability Alerts', URI => 'https://www.securityfocus.com/rss/vulnerabilities.xml', Description => 'Security Focus Vulnerability Alerts' },
    ++        { Name => 'Threatpost Vulnerability Alerts', URI => 'https://threatpost.com/category/vulnerabilities/feed/', Description => 'Threatpost Vulnerability Alerts' },
    ++        { Name => 'Bugtraq', URI => 'https://seclists.org/rss/bugtraq.rss', Description => 'Bugtraq feed' },
    ++    ]
    ++));
    ++
    + =back
    + 
    ++
    + =head1 Service Level Agreements (SLA)
    + 
    + Read F<docs/AdministrationTutorial.pod>.
    +
     diff --git a/html/Callbacks/RTIR/Elements/Tabs/Privileged b/html/Callbacks/RTIR/Elements/Tabs/Privileged
     --- a/html/Callbacks/RTIR/Elements/Tabs/Privileged
     +++ b/html/Callbacks/RTIR/Elements/Tabs/Privileged
    @@ -31,6 +72,27 @@
      
      my $request_path = $HTML::Mason::Commands::r->path_info;
      $request_path =~ s!/{2,}!/!g;
    +
    +diff --git a/html/RTIR/Incident/Create.html b/html/RTIR/Incident/Create.html
    +--- a/html/RTIR/Incident/Create.html
    ++++ b/html/RTIR/Incident/Create.html
    +@@
    + % }
    + 
    + <input type="hidden" name="id"           value="new" />
    ++<input type="hidden" class="hidden" name="new-RefersTo" value="<% $ARGS{'new-RefersTo'} %>" />
    + <input type="hidden" class="hidden" name="Token" value="<% $ARGS{'Token'} %>" />
    + <input type="hidden" name="QueueChanged" value="0" />
    + % if ( $ChildObj ) {
    +@@
    +         $checks_failure = 1;
    +     }
    + 
    ++    my $links = ProcessLinksForCreate(ARGSRef => \%ARGS);
    ++
    +     $checks_failure += RT::IR->FilterRTAddresses(
    +         ARGSRef => \%ARGS,
    +         Fields => { Requestors => 'Requestor', Cc => 'Cc', AdminCc => 'AdminCc' },
     
     diff --git a/html/RTIR/Tools/ExternalFeeds.html b/html/RTIR/Tools/ExternalFeeds.html
     new file mode 100644
    @@ -86,15 +148,20 @@
     +%# END BPS TAGGED BLOCK }}}
     +
     +<& /RTIR/Elements/Header, Title => $title &>
    -+<& /Elements/Tabs &>
    ++  <& /Elements/Tabs &>
    ++<div class="col-12">
     +% my $i = 0;
     +% if ($FeedName) {
     +%   my $feed = $ExternalFeeds->fetch_rss_feed($FeedName);
     +<&|/Widgets/TitleBox,
     +    title => $feed->{Title},
    -+    class => "fullwidth",
    ++    class => "external-feeds fullwidth",
     +    bodyclass => "",
    -+&>
    ++  &>
    ++% if ($feed->{__error}) {
    ++<p> <% $feed->{__error} %> </p>
    ++% }
    ++% else {
     +<div class="table-responsive">
     +  <% $feed->{Description} %>
     +% if ( $feed->{PubDate} || $feed->{LastBuildDate}) {
    @@ -104,11 +171,14 @@
     +  <tr class="collection-as-table">
     +    <th class="collection-as-table"><&|/l&>Name</&></th>
     +    <th class="collection-as-table"><&|/l&>Created</&></th>
    -+    <th class="collection-as-table"><% loc('Create a new [_1]', $ticket_type) %></th>
    ++    <th class="collection-as-table">
    ++      <% loc('Create a new [_1]', $ticket_type) %>
    ++      <span class="far fa-question-circle icon-helper" data-toggle="tooltip" data-placement="top" data-original-title="<&|/l&>This will take you to a partially prefilled creation form.</&>"></span>
    ++    </th>
     +</tr>
     +<tbody class="list-item">
     +%   foreach my $item (@{ $feed->{items} }) {
    -+%      my $GeneratedSubject = sprintf('Incident from RSS feed %s : %s', $feed->{Title}, $item->{Title});
    ++%      my $GeneratedSubject = sprintf('%s : %s', $feed->{Title}, $item->{Title});
     +%      my $GeneratedMessage = join("\n",
     +%         sprintf('Incident created from RSS feed %s : %s', $feed->{Title}, $item->{Title}),
     +%         sprintf('Source : %s on %s', $item->{Link} , $item->{PubDate} || $item->{LastBuildDate} || '-'),
    @@ -120,36 +190,32 @@
     +      <form action="<% $CreateURI %>" name="CreateIncident-<% $i %>" id="CreateIncident-<% $i %>"  method="post">
     +        <input type="hidden" value="<% $GeneratedSubject %>" name="Subject">
     +        <input type="hidden" value="<% $GeneratedMessage %>" name="Content">
    -+        <& /RTIR/Elements/SelectRTIRQueue,
    -+                                Name => 'Queue',
    -+                                ShowNullOption => 0,
    -+                                Lifecycle => $Lifecycle,
    -+                                LimitToConstituency => 1,
    -+                                Constituency => $m->{'RTIR_ConstituencyFilter'} &>
    -+          <& /Elements/Submit, Label => loc("Go"), Caption => loc("This will take you to a partially prefilled [_1] creation form.", $ticket_type) &>
    ++        <input type="hidden" value="<% $item->{Link} %>" Name="new-RefersTo">
    ++        <input type="hidden" value="<% $Lifecycle %>" Name="Lifecycle">
    ++        <input type="submit" class="button btn btn-primary form-control" value="<&|/l&>Create new ticket</&>" />
     +      </form>
     +    </td>
     +  </tr>
     +
    -+
     +  <tr class="<% $i%2 ? 'oddline' : 'evenline' %>">
    -+    <td class="collection-as-table" colspan="3"><small><% $item->{Description} %></small></td>
    ++    <td class="collection-as-table" colspan="3"><small><% $item->{scrubbed_description} |n%></small></td>
     +  </tr>
     +% $i++;
     +%   }
     +</tbody>
     +</table>
     +</div>
    ++% }
     +</&>
    -+% }
    -+% else {
    ++% } else {
     +<&|/Widgets/TitleBox,
     +    title => loc("RSS"),
     +    class => "fullwidth",
     +    bodyclass => ""
    -+&>
    -+<table border="0" cellspacing="0" cellpadding="1" width="100%" class="table queue-summary">
    -+<tr>
    ++  &>
    ++% if ($ExternalFeeds->have_rss_feeds) {
    ++<table cellspacing="0" class="table collection collection-as-table">
    ++<tr class="collection-as-table">
     +<th class="collection-as-table"><&|/l&>Name</&></th>
     +<th class="collection-as-table"><&|/l&>Description</&></th>
     +</tr>
    @@ -161,8 +227,17 @@
     +% $i++;
     +%    }
     +</table>
    ++% }
    ++% else {
    ++<p>
    ++  No RSS feeds currently configured, you can configure feeds in the %ExternalFeeds option of etc/RT_SiteConfig.pm or etc/RT_SiteConfig.d/RT_SiteConfig.pm, a default set of security feeds is included in the inital RTIR configuration.
    ++</p>
    ++
    ++% }
     +</&>
     +% }
    ++</div>
    ++
     +<%INIT>
     +use URI::Escape;
     +use RT::IR::ExternalFeeds;
    @@ -253,21 +328,35 @@
     +        @_,
     +    );
     +    $self->{ua} = LWP::UserAgent->new(timeout => 20);
    -+    $self->{rss_feeds} = {
    -+        map { $_->{Name} => $_ }
    -+        @{RT->Config->Get('ExternalFeeds')->{RSS}}
    -+    };
    -+    $self->{_rss_parser} =  XML::RSS->new();
    ++    $self->{rss_feeds} = { };
    ++    $self->{have_rss_feeds} = 0;
    ++
    ++    if (RT->Config->Get('ExternalFeeds')->{RSS}) {
    ++        my $i = 1;
    ++        foreach my $rss_feed ( @{RT->Config->Get('ExternalFeeds')->{RSS}} ) {
    ++            next unless (ref $rss_feed eq 'HASH');
    ++            $rss_feed->{index} = $i++;
    ++            $self->{rss_feeds}{$rss_feed->{Name}} = $rss_feed;
    ++            $self->{have_rss_feeds} ||= 1;
    ++        }
    ++    }
    ++    $self->{_rss_parser} = XML::RSS->new();
    ++
     +}
     +
     +sub rss_feeds {
     +    my $self = shift;
    -+    return values %{$self->{rss_feeds}};
    ++    return sort { $a->{index} <=> $b->{index} } values %{$self->{rss_feeds}};
    ++}
    ++
    ++sub have_rss_feeds {
    ++    return shift()->{have_rss_feeds};
     +}
     +
     +sub fetch_rss_feed {
     +    my ($self, $name) = @_;
     +    my $url = $self->{rss_feeds}{$name}{URI};
    ++    # make sure we have a fairly short timeout so page doesn't get apache timeout.
     +    my $response = $self->{ua}->get($url);
     +    return $self->_parse_rss_feed($response);
     +}
    @@ -276,8 +365,12 @@
     +
     +sub _parse_rss_feed {
     +    my ($self, $response) = @_;
    -+    return { }  unless ($response->is_success);
    -+    $self->{_rss_parser}->parse($response->content);
    ++    return { __error => "Can't reach feed : " . $response->status_line } unless ($response->is_success);
    ++    eval { $self->{_rss_parser}->parse($response->content); };
    ++    unless ( $self->{_rss_parser}{channel}{title} && $self->{_rss_parser}{items}[0] ) {
    ++        return { __error => "Couldn't parse RSS response "};
    ++    }
    ++
     +    my $parsed_feed = { map { ucfirst($_) => $self->{_rss_parser}{channel}{$_} }
     +                            ( qw(title description pubDate lastBuildDate) ) };
     +    foreach my $item (@{$self->{_rss_parser}{items}}) {
    @@ -288,13 +381,48 @@
     +        $item_values->{Link} //= $item_values->{Url};
     +        if (defined( $item->{'description'} ) ) {
     +            $item_values->{Description} = decode_entities($item->{'description'});
    ++            $item_values->{scrubbed_description} = $self->_scrub_html($item_values->{Description});
     +        } else {
    -+            $item_values->{Description} = 'No content/description for this item';
    ++            $item_values->{scrubbed_description} = $item_values->{Description} = 'No content/description for this item';
     +        }
     +        push (@{$parsed_feed->{items}}, $item_values);
     +    }
     +    return $parsed_feed;
     +}
     +
    ++sub _scrub_html {
    ++    my ($self, $html) = @_;
    ++    unless ($self->{_scrubber}) {
    ++        my $scrubber = HTML::Scrubber->new( script => 0, allow => [ qw[ p b i u br ] ] );
    ++        $scrubber->rules(
    ++            a => {
    ++                'href' => qr{^(?:http|https)://}i,
    ++                '*' =>  0
    ++            },
    ++            '*' => 0
    ++        );
    ++        $self->{_scrubber} = $scrubber;
    ++    }
    ++    my $scrubbed_html = $self->{_scrubber}->scrub($html);
    ++    $scrubbed_html =~ s|<\/?p>|<br>|gi;
    ++    return $scrubbed_html;
    ++}
    ++
     +1;
     
    +diff --git a/static/css/rtir-styles.css b/static/css/rtir-styles.css
    +--- a/static/css/rtir-styles.css
    ++++ b/static/css/rtir-styles.css
    +@@
    + body.rtir table.lookup-tool-forms td {
    +     vertical-align: middle;
    + }
    ++
    ++body.rtir .titlebox.external-feeds tr.oddline+.oddline .collection-as-table,
    ++body.rtir .titlebox.external-feeds tr.evenline+.evenline .collection-as-table {
    ++    padding-bottom: 0.7rem;
    ++}
    ++
    ++body.rtir .titlebox.external-feeds .collection-as-table .unclip {
    ++    margin-top: 0.3rem;
    ++}
2: c0b4b717 < -:  ------- Code review improvements to RSS Feeds
3: ed603963 < -:  ------- Small cleanup of External Feeds HTML



More information about the rt-commit mailing list