From 5917f21991d2dbf1eaf688c54c811761780a17be Mon Sep 17 00:00:00 2001
From: Daniel Collis-Puro
Date: Sun, 19 Jun 2005 22:14:12 +0000
Subject: [PATCH] Updates to SyndicatedContent to allow for content
republishing and MIME-types to Snippets.
---
docs/upgrades/upgrade_6.6.3-6.7.0.sql | 1 +
lib/WebGUI/Asset/Snippet.pm | 21 +++-
lib/WebGUI/Asset/Wobject/SyndicatedContent.pm | 101 +++++++++++++++++-
lib/WebGUI/i18n/English/Asset_Snippet.pm | 10 ++
.../i18n/English/Asset_SyndicatedContent.pm | 27 ++++-
5 files changed, 153 insertions(+), 7 deletions(-)
diff --git a/docs/upgrades/upgrade_6.6.3-6.7.0.sql b/docs/upgrades/upgrade_6.6.3-6.7.0.sql
index 6f7b5391c..de803e261 100644
--- a/docs/upgrades/upgrade_6.6.3-6.7.0.sql
+++ b/docs/upgrades/upgrade_6.6.3-6.7.0.sql
@@ -1,4 +1,5 @@
insert into webguiVersion values ('6.7.0','upgrade',unix_timestamp());
alter table SyndicatedContent add column displayMode varchar(20) not null default 'interleaved';
alter table SyndicatedContent add column hasTerms varchar(255) not null;
+alter table snippet add column mimeType varchar(50) not null default 'text/html';
diff --git a/lib/WebGUI/Asset/Snippet.pm b/lib/WebGUI/Asset/Snippet.pm
index 467469162..9a0c3448c 100644
--- a/lib/WebGUI/Asset/Snippet.pm
+++ b/lib/WebGUI/Asset/Snippet.pm
@@ -18,6 +18,7 @@ use strict;
use WebGUI::Asset;
use WebGUI::Asset::Template;
use WebGUI::Macro;
+use WebGUI::HTTP;
use WebGUI::Session;
our @ISA = qw(WebGUI::Asset);
@@ -29,7 +30,7 @@ Package WebGUI::Asset::Snippet
=head1 DESCRIPTION
-Provides a mechanism to publish arbitrary code snippets to WebGUI for reuse in other pages. Can be used for things like HTML segments, javascript, and cascading style sheets.
+Provides a mechanism to publish arbitrary code snippets to WebGUI for reuse in other pages. Can be used for things like HTML segments, javascript, and cascading style sheets. You can also specify the MIME type of the snippet, allowing you to serve XML, CSS and other text files directly from the WebGUI asset system and have browsers recognize them correctly.
=head1 SYNOPSIS
@@ -70,7 +71,12 @@ sub definition {
processAsTemplate=>{
fieldType=>'yesNo',
defaultValue=>0
+ },
+ mimeType=>{
+ fieldType=>'text',
+ defaultValue=>'text/html'
}
+
}
});
return $class->SUPER::definition($definition);
@@ -89,6 +95,10 @@ Returns the TabForm object that will be used in generating the edit page for thi
sub getEditForm {
my $self = shift;
my $tabform = $self->SUPER::getEditForm();
+ my %mimeTypes;
+ foreach ('text/html','text/css','text/javascript','text/plain','text/xml','application/xml') {
+ $mimeTypes{$_}=$_;
+ }
$tabform->getTab("properties")->codearea(
-name=>"snippet",
-label=>WebGUI::International::get('snippet', 'Asset_Snippet'),
@@ -99,6 +109,13 @@ sub getEditForm {
-label=>WebGUI::International::get('process as template', 'Asset_Snippet'),
-value=>$self->getValue("processAsTemplate")
);
+ $tabform->getTab("properties")->combo(
+ -name=>"mimeType",
+ -label=>WebGUI::International::get('mimeType', 'Asset_Snippet'),
+ -value=>[$self->getValue('mimeType')],
+ -options=>\%mimeTypes
+ );
+
return $tabform;
}
@@ -180,6 +197,8 @@ A web accessible version of the view method.
sub www_view {
my $self = shift;
+ my $mimeType=$self->getValue('mimeType');
+ WebGUI::HTTP::setMimeType($mimeType || 'text/html');
return $self->view(1);
}
diff --git a/lib/WebGUI/Asset/Wobject/SyndicatedContent.pm b/lib/WebGUI/Asset/Wobject/SyndicatedContent.pm
index 627cedb1f..3328a0bfb 100644
--- a/lib/WebGUI/Asset/Wobject/SyndicatedContent.pm
+++ b/lib/WebGUI/Asset/Wobject/SyndicatedContent.pm
@@ -23,8 +23,11 @@ use WebGUI::Privilege;
use WebGUI::Session;
use WebGUI::Asset::Wobject;
use XML::RSSLite;
+use XML::RSS::Creator;
use LWP::UserAgent;
use WebGUI::ErrorHandler;
+use WebGUI::URL;
+use WebGUI::HTTP;
use POSIX qw/floor/;
my $hasEncode=1;
eval " use Encode qw(from_to); "; $hasEncode=0 if $@;
@@ -523,14 +526,18 @@ Returns the rendered output of the wobject.
sub view {
my $self = shift;
+ my $rssFlavor = shift;
$self->logView() if ($session{setting}{passiveProfilingEnabled});
my $maxHeadlines = $self->get("maxHeadlines") || 1000000;
my @urls = split(/\s+/,$self->get("rssUrl"));
+ #We came into this subroutine as
+ my $rssObject=($rssFlavor) ? XML::RSS::Creator->new(version=>$rssFlavor) : undef;
+
my %var;
- my($item_loop,$rss_feeds)=$self->_get_items(\@urls, $maxHeadlines);
+ my($item_loop,$rss_feeds)=$self->_get_items(\@urls, $maxHeadlines,$rssObject);
if(@$rss_feeds > 1){
#If there is more than one (valid) feed in this wobject, put in the wobject description info.
$var{'channel.title'} = $self->get("title");
@@ -541,11 +548,56 @@ sub view {
$var{"channel.link"} = $rss_feeds->[0]->{channel}->{link};
$var{"channel.description"} = $rss_feeds->[0]->{channel}->{description};
}
+ $self->_createRSSURLs(\%var);
$var{item_loop} = $item_loop;
+
+ if ($rssObject) {
+ $self->_constructRSS($rssObject,\%var);
+ my $rss=$rssObject->as_string;
+ WebGUI::HTTP::setMimeType('text/xml');
+
+ #Looks like a kludge, but what this does is put in the proper
+ #XSLT stylesheet so the RSS doesn't look like total ass.
+ my $siteURL=WebGUI::URL::getSiteURL().WebGUI::URL::gateway();
+ $rss=~s|<\?xml version="1\.0" encoding="UTF\-8"\?>|<\?xml version="1\.0" encoding="UTF\-8"\?>\n\n|;
+ return $rss;
+
+ } else {
+ return $self->processTemplate(\%var,$self->get("templateId"));
+ }
- return $self->processTemplate(\%var,$self->get("templateId"));
}
+sub _constructRSS{
+ my($self,$rssObject,$var)=@_;
+ #They've chosen to emit this as an RSS feed, in one of the four flavors we support.
+ $rssObject->channel(
+ title=>$var->{'channel.title'} || $self->get('title'),
+ link=>WebGUI::URL::page('',1),
+ description=>$var->{'channel.description'} || ''
+ );
+ foreach my $item (@{$var->{item_loop}}) {
+ # I know this seems kludgy, but because XML::RSSLite parses
+ # feeds loosely, sometimes it returns a data structure when it shouldn't.
+ # So we're only pushing in attributes when they AREN'T a reference to
+ # a data structure.
+ my %attributes;
+ foreach my $attribute(keys %$item){
+ $attributes{$attribute}=$item->{$attribute} if (! ref($item->{$attribute}));
+ }
+ $rssObject->add_item(%attributes);
+ }
+}
+
+
+sub _createRSSURLs{
+ my $self=shift;
+ my $var=shift;
+ foreach({ver=>'1.0',param=>'10'},{ver=>'0.9',param=>'090'},{ver=>'0.91',param=>'091'},{ver=>'2.0',param=>'20'}){
+ $var->{'rss.url.'.$_->{ver}}=$self->getUrl('func=viewRSS'.$_->{param});
+ }
+ $var->{'rss.url'}=$self->getUrl('func=viewRSS20');
+}
=head2 www_edit()
@@ -560,6 +612,51 @@ sub www_edit {
return $self->getAdminConsole->render($self->getEditForm->print,WebGUI::International::get("4","Asset_SyndicatedContent"));
}
+=head2 www_viewRSS090()
+
+Emit an RSS 0.9 feed.
+
+=cut
+
+sub www_viewRSS090{
+ my $self=shift;
+ return $self->view('0.9');
+}
+
+=head2 www_viewRSS091()
+
+Emit an RSS 0.91 feed.
+
+=cut
+
+sub www_viewRSS091{
+ my $self=shift;
+ return $self->view('0.91');
+}
+
+=head2 www_viewRSS10()
+
+Emit an RSS 1.0 feed.
+
+=cut
+
+sub www_viewRSS10{
+ my $self=shift;
+ return $self->view('1.0');
+}
+
+
+=head2 www_viewRSS20()
+
+Emit an RSS 2.0 feed.
+
+=cut
+
+sub www_viewRSS20{
+ my $self=shift;
+ return $self->view('2.0');
+}
+
1;
diff --git a/lib/WebGUI/i18n/English/Asset_Snippet.pm b/lib/WebGUI/i18n/English/Asset_Snippet.pm
index b159162b6..165c696ff 100644
--- a/lib/WebGUI/i18n/English/Asset_Snippet.pm
+++ b/lib/WebGUI/i18n/English/Asset_Snippet.pm
@@ -13,6 +13,12 @@ our $I18N = {
lastUpdated => 1104630516,
},
+ 'mimeType' => {
+ message => q|MIME Type|,
+ lastUpdated => 1104630516,
+ },
+
+
'snippet add/edit title' => {
message => q|Snippet, Add/Edit|,
lastUpdated => 1104630516,
@@ -30,6 +36,10 @@ This is the snippet. Either type it in or copy and paste it into the form field
Process as template?
This will run the snippet through the template engine. It will enable you to use session variables in the snippet, but it is a little slower.
+
+MIME Type
+Allows you to specify the MIME type of this asset when viewed via the web, useful if you'd like to serve CSS, plain text, javascript or other text files directly from the WebGUI asset system. Defaults to text/html.
+
|,
context => 'Describing snippets and its sole field.',
lastUpdated => 1106683569,
diff --git a/lib/WebGUI/i18n/English/Asset_SyndicatedContent.pm b/lib/WebGUI/i18n/English/Asset_SyndicatedContent.pm
index a8a62d73b..fdd1b5f5b 100644
--- a/lib/WebGUI/i18n/English/Asset_SyndicatedContent.pm
+++ b/lib/WebGUI/i18n/English/Asset_SyndicatedContent.pm
@@ -25,9 +25,9 @@ our $I18N = {
'lastUpdated' => 1110070203,
'message' => 'Syndicated content is content that is pulled from another site using the RDF/RSS specification. This technology is often used to pull headlines from various news sites like CNN and Slashdot. It can, of course, be used for other things like sports scores, stock market info, etc.
-Some terminology: RSS "feeds" (or "channels") are published by websites as collections of "items."
+The Syndicated Content system also has the ability to "republish" it\'s items as RSS 0.9, 0.91, 1.0 and 2.0 flavor feeds. This means you can aggregate a bunch of feeds together, filter on relevant keywords and then republish this aggregated feed, and the Syndicated Content wobject will take care of all the messy stuff for you. See the "Syndicated Content Template" help for additional information.
-This Syndicated Content client is a Wobject and an Asset, so it has the properties of both. It also has
+The Syndicated Content client is a Wobject and an Asset, so it has the properties of both. It also has
these unique properties:
@@ -72,8 +72,6 @@ Enter the maximum number of headlines that should be displayed. Set to zero to
'lastUpdated' => 1047855526,
'message' => 'The following are the template variables available to the Syndicated Content template.
-
-
channel.title
The title of this piece of syndicated content. This will be the same as the title of the Syndicated Content object when you\'re creating an aggregate feed.
@@ -86,6 +84,27 @@ A description of the content available through this channel. This will be the sa
A URL back to the originating site of this channel. This variable *will not* exist when you\'re creating an aggregate feed, because there\'s no single channel to link to.
+rss.url
+This is the URL to use to get the contents of this Syndicated Content wobject as an RSS 2.0 feed. Additionally, you can specify RSS versions via the following template variables:
+
+
+rss.url.0.9
+The contents of this wobject as an RSS 0.9 feed.
+
+rss.url.0.91
+The contents of this wobject as an RSS 0.91 feed.
+
+rss.url.1.0
+The contents of this wobject as an RSS 1.0 feed.
+
+rss.url.2.0
+The contents of this wobject as an RSS 2.0 feed.
+
+
+
+Additionally, RSS feeds are transformed into HTML via XSLT stylesheets for "friendly" in-browser viewing. These XSLT stylesheets are stored in the WebGUI collateral system as snippets.
+
+
item_loop
A loop containing the data from this channel.