(Matthew Wilson) add AssetAspect/RssFeed. See exportAssetCollateral for a good time.

This commit is contained in:
Matthew Wilson 2009-03-30 21:38:12 +00:00
parent 4e78593395
commit cf63a4e4f3
10 changed files with 762 additions and 108 deletions

View file

@ -10,6 +10,13 @@
sku's view screen for the whole form. [TEMPLATE]
- fixed #9933: Matrix 2.0 - Unable to view/edit product maintainer account
- fixed #9951: Matrix 2.0: Median not calculated correctly
- added new AssetAspect::RssFeed (Matthew Wilson) - to convert an asset to use it (see
Collaboration.pm as an example), inherit from Class::C3 as in Collaboration
and you'll need to remove all your ->SUPER::xxxxx invocations - usually replace it
with ->next::method, but when your SUPER was previously calling a method with
a name different from your current method, you'll need to specify the parent/super
module name explicity (e.g. ->WebGUI::Asset::Wobject::canEdit()). You'll also
need to implement the getRssFeedItems method as explained in AssetAspect/RssFeed.pm
7.7.1
- the AdSku project: create a Sku that allows buyers to purchase advertising in select AdSpaces at selected priorities

View file

@ -33,6 +33,9 @@ my $session = start(); # this line required
# upgrade functions go here
recalculateMatrixListingMedianValue( $session );
addRssFeedAspect($session);
addRssFeedAspectToAssets($session);
removeRssCapableAsset($session);
finish($session); # this line required
@ -68,6 +71,49 @@ category = ?",[$medianValue,$listing->{listingId},$category]);
print "Done.\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub addRssFeedAspect {
my $session = shift;
print "\tAdding RssFeed asset aspect..." unless $quiet;
$session->db->write("create table assetAspectRssFeed (
assetId char(22) binary not null,
revisionDate bigint not null,
itemsPerFeed int(11) default 25,
feedCopyright text,
feedTitle text,
feedDescription mediumtext,
feedImage char(22) binary,
feedImageLink text,
feedImageDescription mediumtext,
primary key (assetId, revisionDate)
)");
print "Done.\n" unless $quiet;
}
#----------------------------------------------------------------------------
sub addRssFeedAspectToAssets {
my $session = shift;
foreach my $asset_class (qw( WikiMaster Collaboration SyndicatedContent Gallery GalleryAlbum )) {
print "\tAdding RssFeed aspect to $asset_class table..." unless $quiet;
my $db = $session->db;
my $pages = $db->read("select assetId,revisionDate from $asset_class");
while (my ($id, $rev) = $pages->array) {
$db->write("insert into assetAspectRssFeed (assetId, revisionDate, itemsPerFeed, feedTitle, feedDescription, feedImage, feedImageLink, feedImageDescription) values (?,?,25,'','',NULL,'','')",[$id,$rev]);
}
print "Done.\n" unless $quiet;
}
}
#----------------------------------------------------------------------------
sub removeRssCapableAsset {
my $session = shift;
print "\tRemoving prior RssCapable asset..." unless $quiet;
$session->db->write("drop table RSSCapable");
$session->db->write("drop table RSSFromParent");
print "Done.\n" unless $quiet;
}
#----------------------------------------------------------------------------
# Describe what our function does
#sub exampleFunction {

View file

@ -20,9 +20,9 @@ use WebGUI::Paginator;
use WebGUI::Utility;
use WebGUI::Asset::Wobject;
use WebGUI::Workflow::Cron;
use WebGUI::Asset::RSSCapable;
use base 'WebGUI::Asset::RSSCapable';
use base 'WebGUI::Asset::Wobject';
use Class::C3;
use base qw(WebGUI::AssetAspect::RssFeed WebGUI::Asset::Wobject);
#-------------------------------------------------------------------
sub _computePostCount {
@ -77,12 +77,11 @@ sub addChild {
my $self = shift;
my $properties = shift;
my @other = @_;
if ($properties->{className} ne "WebGUI::Asset::Post::Thread"
and $properties->{className} ne 'WebGUI::Asset::RSSFromParent') {
if ($properties->{className} ne "WebGUI::Asset::Post::Thread") {
$self->session->errorHandler->security("add a ".$properties->{className}." to a ".$self->get("className"));
return undef;
}
return $self->SUPER::addChild($properties, @other);
return $self->next::method($properties, @other);
}
@ -263,7 +262,7 @@ sub canEdit {
) &&
$self->canStartThread( $userId )
) || # account for new threads
$self->SUPER::canEdit( $userId )
$self->next::method( $userId )
);
}
@ -271,7 +270,7 @@ sub canEdit {
sub canModerate {
my $self = shift;
my $userId = shift || $self->session->user->userId;
return $self->SUPER::canEdit( $userId );
return $self->WebGUI::Asset::Wobject::canEdit( $userId );
}
#-------------------------------------------------------------------
@ -294,7 +293,7 @@ sub canPost {
}
# Users who can edit the collab can post
else {
return $self->SUPER::canEdit( $userId );
return $self->WebGUI::Asset::Wobject::canEdit( $userId );
}
}
@ -322,7 +321,7 @@ sub canStartThread {
;
return (
$user->isInGroup($self->get("canStartThreadGroupId"))
|| $self->SUPER::canEdit( $userId )
|| $self->WebGUI::Asset::Wobject::canEdit( $userId )
);
}
@ -331,13 +330,13 @@ sub canStartThread {
sub canView {
my $self = shift;
my $userId = shift || $self->session->user->userId;
return $self->SUPER::canView( $userId ) || $self->canPost( $userId );
return $self->next::method( $userId ) || $self->canPost( $userId );
}
#-------------------------------------------------------------------
sub commit {
my $self = shift;
$self->SUPER::commit;
$self->next::method;
my $cron = undef;
if ($self->get("getMailCronId")) {
$cron = WebGUI::Workflow::Cron->new($self->session, $self->get("getMailCronId"));
@ -799,13 +798,13 @@ sub definition {
className=>'WebGUI::Asset::Wobject::Collaboration',
properties=>\%properties,
});
return $class->SUPER::definition($session, $definition);
return $class->next::method($session, $definition);
}
#-------------------------------------------------------------------
sub duplicate {
my $self = shift;
my $newAsset = $self->SUPER::duplicate(@_);
my $newAsset = $self->next::method(@_);
$newAsset->createSubscriptionGroup;
return $newAsset;
}
@ -821,7 +820,7 @@ Add a tab for the mail interface.
sub getEditTabs {
my $self = shift;
my $i18n = WebGUI::International->new($self->session,"Asset_Collaboration");
return ($self->SUPER::getEditTabs(), ['mail', $i18n->get('mail'), 9]);
return ($self->next::method, ['mail', $i18n->get('mail'), 9]);
}
#-------------------------------------------------------------------
@ -838,7 +837,7 @@ sub getNewThreadUrl {
}
#-------------------------------------------------------------------
sub getRssItems {
sub getRssFeedItems {
my $self = shift;
# XXX copied and reformatted this query from www_viewRSS, but why is it constructed like this?
@ -861,7 +860,7 @@ SQL
my $datetime = $self->session->datetime;
my @posts;
my $rssLimit = $self->get('rssCapableRssLimit') || 10;
my $rssLimit = $self->get('itemsPerFeed');
for my $postId (@postIds) {
my $post = WebGUI::Asset->new($self->session, $postId, 'WebGUI::Asset::Post::Thread');
my $postUrl = $siteUrl . $post->getUrl;
@ -882,15 +881,15 @@ SQL
}
}
push @posts, {
push @posts, {
author => $post->get('username'),
title => $post->get('title'),
'link' => $postUrl,
'link' => $postUrl,
guid => $postUrl,
description => $post->get('synopsis'),
epochDate => $post->get('creationDate'),
pubDate => $datetime->epochToMail($post->get('creationDate')),
attachmentLoop => $attachmentLoop,
attachmentLoop => $attachmentLoop,
userDefined1 => $post->get("userDefined1"),
userDefined2 => $post->get("userDefined2"),
userDefined3 => $post->get("userDefined3"),
@ -901,7 +900,7 @@ SQL
last if $rssLimit <= scalar(@posts);
}
return @posts;
return \@posts;
}
#-------------------------------------------------------------------
@ -1067,7 +1066,7 @@ sub getViewTemplateVars {
$var{'user.canPost'} = $self->canPost;
$var{'user.canStartThread'} = $self->canStartThread;
$var{"add.url"} = $self->getNewThreadUrl;
$var{"rss.url"} = $self->getRssUrl;
$var{"rss.url"} = $self->getRssFeedUrl;
$var{'user.isModerator'} = $self->canModerate;
$var{'user.isVisitor'} = ($self->session->user->isVisitor);
$var{'user.isSubscribed'} = $self->isSubscribed;
@ -1173,11 +1172,9 @@ See WebGUI::Asset::prepareView() for details.
sub prepareView {
my $self = shift;
$self->SUPER::prepareView();
$self->next::method;
my $template = WebGUI::Asset::Template->new($self->session, $self->get("collaborationTemplateId")) or die "no good: ".$self->get("collaborationTemplateId");
if ($self->get('rssCapableRssEnabled')) {
$self->session->style->setLink($self->getRssUrl,{ rel=>'alternate', type=>'application/rss+xml', title=>$self->get('title') . ' RSS' });
}
$self->session->style->setLink($self->getRssFeedUrl,{ rel=>'alternate', type=>'application/rss+xml', title=>$self->get('title') . ' RSS' });
$template->prepare($self->getMetaDataAsTemplateVariables);
$self->{_viewTemplate} = $template;
}
@ -1187,7 +1184,7 @@ sub prepareView {
sub processPropertiesFromFormPost {
my $self = shift;
my $updatePrivs = ($self->session->form->process("groupIdView") ne $self->get("groupIdView") || $self->session->form->process("groupIdEdit") ne $self->get("groupIdEdit"));
$self->SUPER::processPropertiesFromFormPost;
$self->next::method;
if ($self->get("subscriptionGroupId") eq "") {
$self->createSubscriptionGroup;
}
@ -1215,7 +1212,7 @@ sub purge {
my $cron = WebGUI::Workflow::Cron->new($self->session, $self->get("getMailCronId"));
$cron->delete if defined $cron;
}
$self->SUPER::purge;
$self->next::method;
}
#-------------------------------------------------------------------
@ -1230,7 +1227,7 @@ sub purgeCache {
my $self = shift;
WebGUI::Cache->new($self->session,"view_".$self->getId)->delete;
WebGUI::Cache->new($self->session,$self->_visitorCacheKey)->delete;
$self->SUPER::purgeCache;
$self->next::method;
}
#-------------------------------------------------------------------
@ -1463,7 +1460,7 @@ sub www_view {
my $self = shift;
my $disableCache = ($self->session->form->process("sortBy") ne "");
$self->session->http->setCacheControl($self->get("visitorCacheTimeout")) if ($self->session->user->isVisitor && !$disableCache);
return $self->SUPER::www_view(@_);
return $self->next::method(@_);
}
1;

View file

@ -11,7 +11,8 @@ package WebGUI::Asset::Wobject::Gallery;
#-------------------------------------------------------------------
use strict;
use base 'WebGUI::Asset::Wobject';
use Class::C3;
use base qw(WebGUI::AssetAspect::RssFeed WebGUI::Asset::Wobject);
use JSON;
use Tie::IxHash;
use WebGUI::International;
@ -338,7 +339,7 @@ sub definition {
properties => \%properties,
};
return $class->SUPER::definition($session, $definition);
return $class->next::method($session, $definition);
}
#----------------------------------------------------------------------------
@ -366,7 +367,7 @@ sub addChild {
return undef;
}
return $self->SUPER::addChild( $properties, @_ );
return $self->next::method( $properties, @_ );
}
#----------------------------------------------------------------------------
@ -740,6 +741,41 @@ sub getPreviousAlbumId {
}
}
#-------------------------------------------------------------------
=head2 getRssFeedItems ()
Returns an array reference of hash references. Each hash reference has a title,
description, link, and date field. The date field can be either an epoch date, an RFC 1123
date, or a ISO date in the format of YYYY-MM-DD HH:MM::SS. Optionally specify an
author, and a guid field.
=cut
sub getRssFeedItems {
my $self = shift;
my $p
= $self->getAlbumPaginator( {
perpage => $self->get('itemsPerFeed'),
} );
my $var = [];
for my $assetId ( @{ $p->getPageData } ) {
my $asset = WebGUI::Asset::Wobject::GalleryAlbum->newPending( $self->session, $assetId );
push @{ $var }, {
'link' => $asset->getUrl,
'guid' => $asset->{_properties}->{ 'assetId' },
'title' => $asset->getTitle,
'description' => $asset->{_properties}->{ 'description' },
'date' => $asset->{_properties}->{ 'creationDate' },
'author' => WebGUI::User->new($self->session, $asset->{_properties}->{ 'ownerUserId' })->username
};
}
return $var;
}
#----------------------------------------------------------------------------
=head2 getSearchPaginator ( rules )
@ -934,7 +970,7 @@ See WebGUI::Asset::prepareView() for details.
sub prepareView {
my $self = shift;
$self->SUPER::prepareView();
$self->next::method();
if ( $self->get("viewDefault") eq "album" && $self->get("viewAlbumAssetId") && $self->get("viewAlbumAssetId")
ne 'PBasset000000000000001') {
@ -1042,7 +1078,7 @@ sub www_add {
return $self->processStyle($i18n->get("error add uncommitted"));
}
return $self->SUPER::www_add( @_ );
return $self->next::method( @_ );
}
#----------------------------------------------------------------------------

View file

@ -11,7 +11,8 @@ package WebGUI::Asset::Wobject::GalleryAlbum;
#-------------------------------------------------------------------
use strict;
use base 'WebGUI::Asset::Wobject';
use Class::C3;
use base qw(WebGUI::AssetAspect::RssFeed WebGUI::Asset::Wobject);
use Carp qw( croak );
use File::Find;
use File::Spec;
@ -77,7 +78,7 @@ sub definition {
properties => \%properties,
};
return $class->SUPER::definition($session, $definition);
return $class->next::method($session, $definition);
}
#----------------------------------------------------------------------------
@ -174,7 +175,7 @@ sub addChild {
return undef;
}
return $self->SUPER::addChild( $properties, @_ );
return $self->next::method( $properties, @_ );
}
#----------------------------------------------------------------------------
@ -400,7 +401,7 @@ sub getCurrentRevisionDate {
return $revisionDate;
}
else {
return $class->SUPER::getCurrentRevisionDate( $session, $assetId );
return $class->next::method( $session, $assetId );
}
}
@ -497,6 +498,41 @@ sub getPreviousAlbum {
return $self->{_previousAlbum};
}
#-------------------------------------------------------------------
=head2 getRssFeedItems ()
Returns an array reference of hash references. Each hash reference has a title,
description, link, and date field. The date field can be either an epoch date, an RFC 1123
date, or a ISO date in the format of YYYY-MM-DD HH:MM::SS. Optionally specify an
author, and a guid field.
=cut
sub getRssFeedItems {
my $self = shift;
my $p
= $self->getFilePaginator( {
perpage => $self->get('itemsPerFeed'),
} );
my $var = [];
for my $assetId ( @{ $p->getPageData } ) {
my $asset = WebGUI::Asset::Wobject::GalleryAlbum->newPending( $self->session, $assetId );
push @{ $var }, {
'link' => $asset->getUrl,
'guid' => $asset->{_properties}->{ 'assetId' },
'title' => $asset->getTitle,
'description' => $asset->{_properties}->{ 'description' },
'date' => $asset->{_properties}->{ 'creationDate' },
'author' => WebGUI::User->new($self->session, $asset->{_properties}->{ 'ownerUserId' })->username
};
}
return $var;
}
#----------------------------------------------------------------------------
=head2 getTemplateVars ( )
@ -639,7 +675,7 @@ See WebGUI::Asset::prepareView() for details.
sub prepareView {
my $self = shift;
$self->SUPER::prepareView();
$self->next::method();
my $templateId = $self->getParent->get("templateIdViewAlbum");
@ -719,7 +755,7 @@ approval workflow.
sub processPropertiesFromFormPost {
my $self = shift;
my $form = $self->session->form;
my $errors = $self->SUPER::processPropertiesFromFormPost || [];
my $errors = $self->next::method || [];
# Return if error
return $errors if @$errors;
@ -762,7 +798,7 @@ Override update to force isHidden=1 on all albums.
sub update {
my $self = shift;
my $properties = shift;
return $self->SUPER::update({ %{ $properties }, isHidden=>1 });
return $self->next::method({ %{ $properties }, isHidden=>1 });
}
#----------------------------------------------------------------------------

View file

@ -17,7 +17,8 @@ use WebGUI::Cache;
use WebGUI::Exception;
use WebGUI::HTML;
use WebGUI::International;
use base 'WebGUI::Asset::Wobject';
use Class::C3;
use base qw(WebGUI::AssetAspect::RssFeed WebGUI::Asset::Wobject);
use WebGUI::Macro;
use XML::FeedPP;
@ -116,7 +117,7 @@ sub definition {
className=>'WebGUI::Asset::Wobject::SyndicatedContent',
properties=>\%properties
});
return $class->SUPER::definition($session, $definition);
return $class->next::method($session, $definition);
}
#-------------------------------------------------------------------
@ -129,6 +130,7 @@ Combines all feeds into a single XML::FeedPP object.
sub generateFeed {
my $self = shift;
my $limit = shift || $self->get('maxHeadlines');
my $feed = XML::FeedPP::Atom->new();
my $log = $self->session->log;
@ -173,8 +175,8 @@ sub generateFeed {
# sort them by date
$feed->sort_item();
# limit the feed to the maxium number of headlines
$feed->limit_item($self->get('maxHeadlines'));
# limit the feed to the maximum number of headlines (or the feed generator limit).
$feed->limit_item($limit);
# mark this asset as updated
$self->update({}) if ($newlyCached);
@ -184,6 +186,53 @@ sub generateFeed {
#-------------------------------------------------------------------
=head2 getFeed ()
Override the one in the parent...
=cut
sub getFeed {
my $self = shift;
my $feed = shift;
foreach my $item ($self->generateFeed( $self->get('itemsPerFeed') )->get_item) {
my $set_permalink_false = 0;
my $new_item = $feed->add_item( $item );
warn "creating item !";
if (!$new_item->guid) {
if ($new_item->link) {
$new_item->guid( $new_item->link );
} else {
$new_item->guid( $self->session->id->generate );
$set_permalink_false = 1;
}
}
$new_item->guid( $new_item->guid, isPermaLink => 0 ) if $set_permalink_false;
}
$feed->title( $self->get('feedTitle') || $self->get('title') );
$feed->description( $self->get('feedDescription') || $self->get('synopsis') );
$feed->pubDate( $self->getContentLastModified );
$feed->copyright( $self->get('feedCopyright') );
$feed->link( $self->getUrl );
# $feed->language( $lang );
if ($self->get('feedImage')) {
my $storage = WebGUI::Storage->get($self->session, $self->get('feedImage'));
my @files = @{ $storage->getFiles };
if (scalar @files) {
$feed->image(
$storage->getUrl( $files[0] ),
$self->get('feedImageDescription') || $self->getTitle,
$self->get('feedImageUrl') || $self->getUrl,
$self->get('feedImageDescription') || $self->getTitle,
( $storage->getSizeInPixels( $files[0] ) ) # expands to width and height
);
}
}
return $feed;
}
#-------------------------------------------------------------------
=head2 getTemplateVariables
Returns a hash reference of template variables.
@ -256,7 +305,7 @@ See WebGUI::Asset::prepareView() for details.
sub prepareView {
my $self = shift;
$self->SUPER::prepareView();
$self->next::method;
my $template = WebGUI::Asset::Template->new($self->session, $self->get("templateId"));
$template->prepare($self->getMetaDataAsTemplateVariables);
$self->{_viewTemplate} = $template;
@ -279,7 +328,7 @@ See WebGUI::Asset::purgeCache() for details.
sub purgeCache {
my $self = shift;
WebGUI::Cache->new($self->session,"view_".$self->getId)->delete;
$self->SUPER::purgeCache;
$self->next::method;
}
#-------------------------------------------------------------------
@ -318,59 +367,7 @@ See WebGUI::Asset::Wobject::www_view() for details.
sub www_view {
my $self = shift;
$self->session->http->setCacheControl($self->get("cacheTimeout"));
$self->SUPER::www_view(@_);
}
#-------------------------------------------------------------------
=head2 www_viewAtom ( )
Emit an Atom 0.3 feed.
=cut
sub www_viewAtom {
my $self = shift;
my $feed = $self->generateFeed;
my $atom = XML::FeedPP::Atom->new;
$atom->merge($feed);
$self->session->http->setMimeType('application/atom+xml');
return $atom->to_string;
}
#-------------------------------------------------------------------
=head2 www_viewRdf ( )
Emit an RSS 1.0 / RDF feed.
=cut
sub www_viewRdf {
my $self = shift;
my $feed = $self->generateFeed;
my $rdf = XML::FeedPP::RDF->new;
$rdf->merge($feed);
$self->session->http->setMimeType('application/rdf+xml');
return $rdf->to_string;
}
#-------------------------------------------------------------------
=head2 www_viewRss ( )
Emit an RSS 2.0 feed.
=cut
sub www_viewRss {
my $self = shift;
my $feed = $self->generateFeed;
my $rss = XML::FeedPP::RSS->new;
$rss->merge($feed);
$self->session->http->setMimeType('application/rss+xml');
return $rss->to_string;
$self->next::method(@_);
}
#-------------------------------------------------------------------

View file

@ -10,7 +10,8 @@ package WebGUI::Asset::Wobject::WikiMaster;
# http://www.plainblack.com info@plainblack.com
#-------------------------------------------------------------------
use base 'WebGUI::Asset::Wobject';
use Class::C3;
use base qw(WebGUI::AssetAspect::RssFeed WebGUI::Asset::Wobject);
use strict;
use Tie::IxHash;
use WebGUI::International;
@ -70,6 +71,7 @@ sub appendRecentChanges {
username=>$user->username,
date=>$self->session->datetime->epochToHuman($asset->get("revisionDate")),
isAvailable=>$isAvailable,
assetId=>$id,
});
}
}
@ -139,7 +141,7 @@ sub autolinkHtml {
#-------------------------------------------------------------------
sub canAdminister {
my $self = shift;
return $self->session->user->isInGroup($self->get('groupToAdminister')) || $self->SUPER::canEdit;
return $self->session->user->isInGroup($self->get('groupToAdminister')) || $self->WebGUI::Asset::Wobject::canEdit;
}
#-------------------------------------------------------------------
@ -164,7 +166,7 @@ sub canEdit {
) &&
$self->canEditPages
) || # account for new posts
$self->SUPER::canEdit()
$self->next::method()
);
}
@ -337,13 +339,44 @@ sub definition {
properties => \%properties,
};
return $class->SUPER::definition($session, $definition);
return $class->next::method($session, $definition);
}
#-------------------------------------------------------------------
=head2 getRssFeedItems ()
Returns an array reference of hash references. Each hash reference has a title,
description, link, and date field. The date field can be either an epoch date, an RFC 1123
date, or a ISO date in the format of YYYY-MM-DD HH:MM::SS. Optionally specify an
author, and a guid field.
=cut
sub getRssFeedItems {
my $self = shift;
my $vars = {};
$self->appendRecentChanges( $vars, $self->get('itemsPerFeed') );
my $var = [];
foreach my $item ( @{ $vars->{recentChanges} } ) {
my $asset = WebGUI::Asset->newByDynamicClass( $self->session, $item->{assetId} );
push @{ $var }, {
'link' => $asset->getUrl,
'guid' => $item->{ 'assetId' } . $asset->get( 'revisionDate' ),
'title' => $asset->getTitle,
'description' => $item->{ 'actionTaken' },
'date' => $item->{ 'date' },
'author' => $item->{ 'username' },
};
}
return $var;
}
#-------------------------------------------------------------------
sub prepareView {
my $self = shift;
$self->SUPER::prepareView;
$self->next::method;
$self->{_frontPageTemplate} =
WebGUI::Asset::Template->new($self->session, $self->get('frontPageTemplateId'));
$self->{_frontPageTemplate}->prepare;
@ -355,7 +388,7 @@ sub processPropertiesFromFormPost {
my $groupsChanged =
(($self->session->form->process('groupIdView') ne $self->get('groupIdView'))
or ($self->session->form->process('groupIdEdit') ne $self->get('groupIdEdit')));
my $ret = $self->SUPER::processPropertiesFromFormPost(@_);
my $ret = $self->next::method(@_);
if ($groupsChanged) {
foreach my $child (@{$self->getLineage(['children'], {returnObjects => 1})}) {
$child->update({ groupIdView => $self->get('groupIdView'),

View file

@ -0,0 +1,398 @@
package WebGUI::AssetAspect::RssFeed;
=head1 LEGAL
-------------------------------------------------------------------
WebGUI is Copyright 2001-2009 Plain Black Corporation.
-------------------------------------------------------------------
Please read the legal notices (docs/legal.txt) and the license
(docs/license.txt) that came with this distribution before using
this software.
-------------------------------------------------------------------
http://www.plainblack.com info@plainblack.com
-------------------------------------------------------------------
=cut
use strict;
use Class::C3;
use WebGUI::Exception;
use WebGUI::Storage;
use XML::FeedPP;
use Path::Class::File;
=head1 NAME
Package WebGUI::AssetAspect::RssFeed
=head1 DESCRIPTION
This is an aspect which exposes an asset's items as an RSS or Atom feed.
=head1 SYNOPSIS
use Class::C3;
use base qw(WebGUI::AssetAspect::RssFeed WebGUI::Asset);
And then wherever you would call $self->SUPER::someMethodName call $self->next::method instead.
=head1 METHODS
These methods are available from this class:
=cut
#-------------------------------------------------------------------
=head2 definition
Extends the definition to add the RSS fields.
=cut
sub definition {
my $class = shift;
my $session = shift;
my $definition = shift;
my $i18n = WebGUI::International->new($session,'AssetAspect_RssFeed');
my %properties;
tie %properties, 'Tie::IxHash';
%properties = (
itemsPerFeed => {
noFormPost => 0,
fieldType => "integer",
defaultValue => 25,
tab => "rss",
label => $i18n->get('itemsPerFeed'),
hoverHelp => $i18n->get('itemsPerFeed hoverHelp')
},
feedCopyright => {
noFormPost => 0,
fieldType => "text",
defaultValue => "",
tab => "rss",
label => $i18n->get('feedCopyright'),
hoverHelp => $i18n->get('feedCopyright hoverHelp')
},
feedTitle => {
noFormPost => 0,
fieldType => "text",
defaultValue => "",
tab => "rss",
label => $i18n->get('feedTitle'),
hoverHelp => $i18n->get('feedTitle hoverHelp')
},
feedDescription => {
noFormPost => 0,
fieldType => "textarea",
defaultValue => "",
tab => "rss",
label => $i18n->get('feedDescription'),
hoverHelp => $i18n->get('feedDescription hoverHelp')
},
feedImage => {
noFormPost => 0,
fieldType => "image",
tab => "rss",
label => $i18n->get('feedImage'),
hoverHelp => $i18n->get('feedImage hoverHelp')
},
feedImageLink => {
noFormPost => 0,
fieldType => "text",
defaultValue => "",
tab => "rss",
label => $i18n->get('feedImageLink'),
hoverHelp => $i18n->get('feedImageLink hoverHelp')
},
feedImageDescription => {
noFormPost => 0,
fieldType => "text",
defaultValue => "",
tab => "rss",
label => $i18n->get('feedImageDescription'),
hoverHelp => $i18n->get('feedImageDescription hoverHelp')
},
);
push(@{$definition}, {
autoGenerateForms => 1,
tableName => 'assetAspectRssFeed',
className => 'WebGUI::AssetAspect::RssFeed',
properties => \%properties
});
return $class->next::method($session, $definition);
}
#-------------------------------------------------------------------
=head2 exportAssetCollateral ()
Extended from WebGUI::Asset and exports the www_viewRss() and
www_viewAtom() methods with filenames generated by
getStaticAtomFeedUrl() and getStaticRssFeedUrl().
This method will be called with the following parameters:
=head3 basePath
A L<Path::Class> object representing the base filesystem path for this
particular asset.
=head3 params
A hashref with the quiet, userId, depth, and indexFileName parameters from
L</exportAsHtml>.
=cut
sub exportAssetCollateral {
# Lots of copy/paste here from AssetExportHtml.pm, since none of the methods there were
# directly useful without ginormous refactoring.
my $self = shift;
my $basepath = shift;
my $args = shift;
my $basename = $basepath->basename;
my $filedir;
my $filenameBase;
# We want our .rss and .atom files to "appear" at the same level as the asset.
if ($basename eq 'index.html') {
# Get the 2nd ancestor, since the asset url had no dot in it (and it therefore
# had its own directory created for it).
$filedir = $basepath->parent->parent->absolute->stringify;
# Get the parent dir's *path* (essentially the name of the dir) relative to
# its own parent dir.
$filenameBase = $basepath->parent->relative( $basepath->parent->parent )->stringify;
} else {
# Get the 1st ancestor, since the asset is a file recognized by apache, so
# we want our files in the same dir.
$filedir = $basepath->parent->absolute->stringify;
# just use the basename.
$filenameBase = $basename;
}
$self->{ '_masterSession' }->output->print('<br />') unless ($args->{quiet});
foreach my $ext (qw( rss atom )) {
my $dest = Path::Class::File->new($filedir, $filenameBase . '.' . $ext);
# tell the user which asset we're exporting.
unless ($args->{quiet}) {
my $message = sprintf $self->{ '_masteri18n' }->get('exporting page'), $dest->absolute->stringify;
$self->{ '_masterSession' }->output->print('&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'.$message);
}
# open another session as the user doing the exporting...
my $tempSession = WebGUI::Session->open($self->session->config->getWebguiRoot,$self->session->config->getFilename);
$tempSession->user( { userId => $self->session->user->userId } );
my $selfdupe = WebGUI::Asset->newByDynamicClass( $tempSession, $self->getId );
# next, get the contents, open the file, and write the contents to the file.
my $fh = eval { $dest->open('>:utf8') };
if($@) {
WebGUI::Error->throw(error => "can't open " . $dest->absolute->stringify . " for writing: $!");
}
my $previousHandle = $selfdupe->session->{_handle};
my $previousDefaultAsset = $selfdupe->session->asset;
$selfdupe->session->asset($selfdupe);
$selfdupe->session->output->setHandle($fh);
my $contents;
if ($ext eq 'rss') {
$contents = $selfdupe->www_viewRss;
} else {
$contents = $selfdupe->www_viewAtom;
} # add more for more extensions.
# chunked content is already printed, no need to print it again
unless($contents eq 'chunked') {
$tempSession->output->print($contents);
}
$tempSession->output->setHandle($previousHandle);
# properly close the temp session
$tempSession->var->end;
$tempSession->close;
# tell the user we did this asset collateral correctly
unless( $args->{quiet} ) {
$self->{ '_masterSession' }->output->print($self->{ '_masteri18n' }->get('done'));
}
}
return $self->next::method($basepath, $args);
}
#-------------------------------------------------------------------
=head2 getRssFeedItems ()
This method should throw an exception if it's not overridden. Its intention is
to be overridden by whatever class is using it and should return an array
reference of hash references. Each hash reference should contain at minimum a title,
description, link, and date field. The date field can be either an epoch date, an RFC 1123
date, or a ISO date in the format of YYYY-MM-DD HH:MM::SS. Optionally specify an
author, and a guid field.
=cut
sub getRssFeedItems {
WebGUI::Error::OverrideMe->throw();
}
#-------------------------------------------------------------------
=head2 getAtomFeedUrl ()
Returns $self->getUrl(func=viewAtom).
=cut
sub getAtomFeedUrl {
shift->getUrl("func=viewAtom");
}
#-------------------------------------------------------------------
=head2 getRssFeedUrl ()
Returns $self->getUrl(func=viewRss).
=cut
sub getRssFeedUrl {
shift->getUrl("func=viewRss");
}
#-------------------------------------------------------------------
=head2 getStaticAtomFeedUrl ()
Returns the current asset's URL with .atom concatenated onto it.
=cut
sub getStaticAtomFeedUrl {
shift->getUrl() . '.atom';
}
#-------------------------------------------------------------------
=head2 getStaticRssFeedUrl ()
Returns the current asset's URL with .rss concatenated onto it.
=cut
sub getStaticRssFeedUrl {
shift->getUrl() . '.rss';
}
#-------------------------------------------------------------------
=head2 getFeed ()
Adds the syndicated items to the feed; returns the stringified edition.
TODO: convert dates?
=cut
sub getFeed {
my $self = shift;
my $feed = shift;
foreach my $item ( @{ $self->getRssFeedItems } ) {
my $set_permalink_false = 0;
my $new_item = $feed->add_item( %{ $item } );
if (!$new_item->guid) {
if ($new_item->link) {
$new_item->guid( $new_item->link );
} else {
$new_item->guid( $self->session->id->generate );
$set_permalink_false = 1;
}
}
$new_item->guid( $new_item->guid, isPermaLink => 0 ) if $set_permalink_false;
}
$feed->title( $self->get('feedTitle') || $self->get('title') );
$feed->description( $self->get('feedDescription') || $self->get('synopsis') );
$feed->pubDate( $self->getContentLastModified );
$feed->copyright( $self->get('feedCopyright') );
$feed->link( $self->getUrl );
# $feed->language( $lang );
if ($self->get('feedImage')) {
my $storage = WebGUI::Storage->get($self->session, $self->get('feedImage'));
my @files = @{ $storage->getFiles };
if (scalar @files) {
$feed->image(
$storage->getUrl( $files[0] ),
$self->get('feedImageDescription') || $self->getTitle,
$self->get('feedImageUrl') || $self->getUrl,
$self->get('feedImageDescription') || $self->getTitle,
( $storage->getSizeInPixels( $files[0] ) ) # expands to width and height
);
}
}
return $feed;
}
#-------------------------------------------------------------------
=head2 www_viewAtom ()
Return Atom view of the syndicated items.
=cut
sub www_viewAtom {
my $self = shift;
$self->session->http->setMimeType('application/atom+xml');
return $self->getFeed( XML::FeedPP::Atom->new )->to_string;
}
#-------------------------------------------------------------------
=head2 www_viewRdf ()
Return Rdf view of the syndicated items.
=cut
sub www_viewRdf {
my $self = shift;
$self->session->http->setMimeType('application/rdf+xml');
return $self->getFeed( XML::FeedPP::Rdf->new )->to_string;
}
#-------------------------------------------------------------------
=head2 www_viewRss ()
Return RSS view of the syndicated items.
=cut
sub www_viewRss {
my $self = shift;
$self->session->http->setMimeType('application/rss+xml');
return $self->getFeed( XML::FeedPP::RSS->new )->to_string;
}
#-------------------------------------------------------------------
=head2 getEditTabs ()
Adds an RSS tab to the Edit Tabs.
=cut
sub getEditTabs {
my $self = shift;
my $i18n = WebGUI::International->new($self->session,'AssetAspect_RssFeed');
return ($self->next::method, ['rss', $i18n->get('RSS tab'), 1]);
}
1;

View file

@ -330,7 +330,12 @@ sub exportAsHtml {
$exportSession->close;
return ($returnCode, $message);
}
# Stash the current session and i18n into the asset so that exportAssetCollateral can
# also write informative messages to the output terminal. :)
$asset->{ '_masterSession' } = $self->session;
$asset->{ '_masteri18n' } = $i18n;
# next, tell the asset that we're exporting, so that it can export any
# of its collateral or other extra data.
eval { $asset->exportAssetCollateral($asset->exportGetUrlAsPath, $args) };

View file

@ -0,0 +1,99 @@
package WebGUI::i18n::English::AssetAspect_RssFeed;
use strict;
our $I18N = {
'itemsPerFeed' => {
message => q|Items Per Feed|,
lastUpdated => 1236820473,
context => q|The name of the itemsPerFeed field.|
},
'itemsPerFeed hoverHelp' => {
message => q|The number of items to include in the feed.|,
lastUpdated => 1236820473,
context => q|The hoverhelp of the itemsPerFeed field.|
},
'feedCopyright' => {
message => q|Feed Copyright|,
lastUpdated => 1236820473,
context => q|The name of the feedCopyright field.|
},
'feedCopyright hoverHelp' => {
message => q|An optional copyright notice for the feed.|,
lastUpdated => 1236820473,
context => q|The hoverhelp of the feedCopyright field.|
},
'feedTitle' => {
message => q|Feed Title|,
lastUpdated => 1236820473,
context => q|The name of the feedTitle field.|
},
'feedTitle hoverHelp' => {
message => q|An optional title for the feed. If not specified the asset's title will be used instead.|,
lastUpdated => 1236820473,
context => q|The hoverhelp of the feedTitle field.|
},
'feedDescription' => {
message => q|Feed Description|,
lastUpdated => 1236820473,
context => q|The name of the feedDescription field.|
},
'feedDescription hoverHelp' => {
message => q|An optional description for the feed. If not specified the asset's synopsis will be used instead.|,
lastUpdated => 1236820473,
context => q|The hoverhelp of the feedDescription field.|
},
'feedImage' => {
message => q|Feed Image|,
lastUpdated => 1236820473,
context => q|The name of the feedImage field.|
},
'feedImage hoverHelp' => {
message => q|An optional image that can be uploaded for the feed.|,
lastUpdated => 1236820473,
context => q|The hoverhelp of the feedImage field.|
},
'feedImageLink' => {
message => q|Feed Image Link|,
lastUpdated => 1236820473,
context => q|The name of the feedImageLink field.|
},
'feedImageLink hoverHelp' => {
message => q|An optional URL that will link the image to a specific location. If not specified the asset's URL will be used instead.|,
lastUpdated => 1236820473,
context => q|The hoverhelp of the feedImageLink field.|
},
'feedImageDescription' => {
message => q|Feed Image Description|,
lastUpdated => 1236820473,
context => q|The name of the feedImageDescription field.|
},
'feedImageDescription hoverHelp' => {
message => q|An optional description for the image. If not specified the asset's title will be used instead.|,
lastUpdated => 1236820473,
context => q|The hoverhelp of the feedImageDescription field.|
},
'RSS tab' => {
message => q|RSS|,
lastUpdated => 1236820473,
context => q|The title of the RSS tab on the asset's edit form.|
},
};
1;
#vim:ft=perl