1907 lines
60 KiB
Perl
1907 lines
60 KiB
Perl
package WebGUI::Asset::Wobject::Collaboration;
|
|
|
|
#-------------------------------------------------------------------
|
|
# 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
|
|
#-------------------------------------------------------------------
|
|
|
|
use strict;
|
|
use Tie::IxHash;
|
|
use Moose;
|
|
use WebGUI::Definition::Asset;
|
|
extends 'WebGUI::Asset::Wobject';
|
|
define assetName => ['assetName', 'Asset_Collaboration'];
|
|
define icon => 'collaboration.gif';
|
|
define tableName => 'Collaboration';
|
|
property visitorCacheTimeout => (
|
|
tab => "display",
|
|
fieldType => "interval",
|
|
default => 3600,
|
|
uiLevel => 8,
|
|
label => [ "visitor cache timeout", 'Asset_Collaboration' ],
|
|
hoverHelp => [ "visitor cache timeout help", 'Asset_Collaboration' ]
|
|
);
|
|
property autoSubscribeToThread => (
|
|
fieldType => "yesNo",
|
|
default => 1,
|
|
tab => 'mail',
|
|
label => [ "auto subscribe to thread", 'Asset_Collaboration' ],
|
|
hoverHelp => [ "auto subscribe to thread help", 'Asset_Collaboration' ],
|
|
);
|
|
property requireSubscriptionForEmailPosting => (
|
|
fieldType => "yesNo",
|
|
default => 1,
|
|
tab => 'mail',
|
|
label => [ "require subscription for email posting", 'Asset_Collaboration' ],
|
|
hoverHelp => [ "require subscription for email posting help", 'Asset_Collaboration' ],
|
|
);
|
|
property approvalWorkflow => (
|
|
fieldType => "workflow",
|
|
default => "pbworkflow000000000003",
|
|
type => 'WebGUI::VersionTag',
|
|
tab => 'security',
|
|
label => [ 'approval workflow', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'approval workflow description', 'Asset_Collaboration' ],
|
|
);
|
|
property threadApprovalWorkflow => (
|
|
fieldType => "workflow",
|
|
default => "pbworkflow000000000003",
|
|
type => 'WebGUI::VersionTag',
|
|
tab => 'security',
|
|
label => [ 'thread approval workflow', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'thread approval workflow description', 'Asset_Collaboration' ],
|
|
);
|
|
property thumbnailSize => (
|
|
fieldType => "integer",
|
|
default => 0,
|
|
tab => "display",
|
|
label => [ "thumbnail size", 'Asset_Collaboration' ],
|
|
hoverHelp => [ "thumbnail size help", 'Asset_Collaboration' ]
|
|
);
|
|
property maxImageSize => (
|
|
fieldType => "integer",
|
|
default => 0,
|
|
tab => "display",
|
|
label => [ "max image size", 'Asset_Collaboration' ],
|
|
hoverHelp => [ "max image size help", 'Asset_Collaboration' ]
|
|
);
|
|
property mailServer => (
|
|
fieldType => "text",
|
|
default => undef,
|
|
tab => 'mail',
|
|
label => [ "mail server", 'Asset_Collaboration' ],
|
|
hoverHelp => [ "mail server help", 'Asset_Collaboration' ],
|
|
);
|
|
property mailAccount => (
|
|
fieldType => "text",
|
|
default => undef,
|
|
tab => 'mail',
|
|
label => [ "mail account", 'Asset_Collaboration' ],
|
|
hoverHelp => [ "mail account help", 'Asset_Collaboration' ],
|
|
extras => 'autocomplete="off"',
|
|
);
|
|
property mailPassword => (
|
|
fieldType => "password",
|
|
default => undef,
|
|
tab => 'mail',
|
|
label => [ "mail password", 'Asset_Collaboration' ],
|
|
hoverHelp => [ "mail password help", 'Asset_Collaboration' ],
|
|
);
|
|
property mailAddress => (
|
|
fieldType => "email",
|
|
default => undef,
|
|
tab => 'mail',
|
|
label => [ "mail address", 'Asset_Collaboration' ],
|
|
hoverHelp => [ "mail address help", 'Asset_Collaboration' ],
|
|
);
|
|
property mailPrefix => (
|
|
fieldType => "text",
|
|
default => undef,
|
|
tab => 'mail',
|
|
label => [ "mail prefix", 'Asset_Collaboration' ],
|
|
hoverHelp => [ "mail prefix help", 'Asset_Collaboration' ],
|
|
);
|
|
property getMailCronId => (
|
|
fieldType => "hidden",
|
|
default => undef,
|
|
noFormPost => 1
|
|
);
|
|
property getMail => (
|
|
fieldType => "yesNo",
|
|
default => 0,
|
|
tab => 'mail',
|
|
label => [ "get mail", 'Asset_Collaboration' ],
|
|
hoverHelp => [ "get mail help", 'Asset_Collaboration' ],
|
|
);
|
|
property getMailInterval => (
|
|
fieldType => "interval",
|
|
default => 300,
|
|
tab => 'mail',
|
|
label => [ "get mail interval", 'Asset_Collaboration' ],
|
|
hoverHelp => [ "get mail interval help", 'Asset_Collaboration' ],
|
|
);
|
|
property displayLastReply => (
|
|
fieldType => "yesNo",
|
|
default => 0,
|
|
tab => 'display',
|
|
label => [ 'display last reply', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'display last reply description', 'Asset_Collaboration' ],
|
|
);
|
|
property allowReplies => (
|
|
fieldType => "yesNo",
|
|
default => 1,
|
|
tab => 'security',
|
|
label => [ 'allow replies', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'allow replies description', 'Asset_Collaboration' ],
|
|
);
|
|
property threadsPerPage => (
|
|
fieldType => "integer",
|
|
default => 30,
|
|
tab => 'display',
|
|
label => [ 'threads/page', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'threads/page description', 'Asset_Collaboration' ],
|
|
);
|
|
property postsPerPage => (
|
|
fieldType => "integer",
|
|
default => 10,
|
|
tab => 'display',
|
|
label => [ 'posts/page', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'posts/page description', 'Asset_Collaboration' ],
|
|
);
|
|
property archiveEnabled => (
|
|
fieldType => "yesNo",
|
|
default => 1,
|
|
tab => 'properties',
|
|
label => [ 'editForm archiveEnabled label', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'editForm archiveEnabled description', 'Asset_Collaboration' ],
|
|
);
|
|
property archiveAfter => (
|
|
fieldType => "interval",
|
|
default => 31536000,
|
|
tab => 'properties',
|
|
label => [ 'archive after', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'archive after description', 'Asset_Collaboration' ],
|
|
);
|
|
property lastPostDate => (
|
|
noFormPost => 1,
|
|
fieldType => "hidden",
|
|
default => undef
|
|
);
|
|
property lastPostId => (
|
|
noFormPost => 1,
|
|
fieldType => "hidden",
|
|
default => undef
|
|
);
|
|
property rating => (
|
|
noFormPost => 1,
|
|
fieldType => "hidden",
|
|
default => undef
|
|
);
|
|
property replies => (
|
|
noFormPost => 1,
|
|
fieldType => "hidden",
|
|
default => undef
|
|
);
|
|
property views => (
|
|
noFormPost => 1,
|
|
fieldType => "hidden",
|
|
default => undef
|
|
);
|
|
property threads => (
|
|
noFormPost => 1,
|
|
fieldType => "hidden",
|
|
default => undef
|
|
);
|
|
property useContentFilter => (
|
|
fieldType => "yesNo",
|
|
default => 1,
|
|
tab => 'display',
|
|
label => [ 'content filter', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'content filter description', 'Asset_Collaboration' ],
|
|
);
|
|
property filterCode => (
|
|
fieldType => "filterContent",
|
|
default => 'most',
|
|
tab => 'security',
|
|
label => [ 'filter code', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'filter code description', 'Asset_Collaboration' ],
|
|
);
|
|
property replyFilterCode => (
|
|
fieldType => "filterContent",
|
|
default => 'most',
|
|
tab => 'security',
|
|
label => [ 'reply filter code', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'reply filter code description', 'Asset_Collaboration' ],
|
|
);
|
|
property richEditor => (
|
|
fieldType => "selectRichEditor",
|
|
default => "PBrichedit000000000002",
|
|
tab => 'display',
|
|
label => [ 'rich editor', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'rich editor description', 'Asset_Collaboration' ],
|
|
);
|
|
property replyRichEditor => (
|
|
fieldType => "selectRichEditor",
|
|
default => "PBrichedit000000000002",
|
|
tab => 'display',
|
|
label => [ 'reply rich editor', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'reply rich editor description', 'Asset_Collaboration' ],
|
|
);
|
|
property attachmentsPerPost => (
|
|
fieldType => "integer",
|
|
default => 0,
|
|
tab => 'properties',
|
|
label => [ 'attachments/post', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'attachments/post description', 'Asset_Collaboration' ],
|
|
);
|
|
property editTimeout => (
|
|
fieldType => "interval",
|
|
default => 3600,
|
|
tab => 'security',
|
|
label => [ 'edit timeout', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'edit timeout description', 'Asset_Collaboration' ],
|
|
);
|
|
property addEditStampToPosts => (
|
|
fieldType => "yesNo",
|
|
default => 0,
|
|
tab => 'security',
|
|
label => [ 'edit stamp', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'edit stamp description', 'Asset_Collaboration' ],
|
|
);
|
|
property usePreview => (
|
|
fieldType => "yesNo",
|
|
default => 1,
|
|
tab => 'properties',
|
|
label => [ 'use preview', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'use preview description', 'Asset_Collaboration' ],
|
|
);
|
|
property sortOrder => (
|
|
fieldType => "selectBox",
|
|
default => 'desc',
|
|
tab => 'display',
|
|
options => \&_sortOrder_options,
|
|
label => [ 'sort order', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'sort order description', 'Asset_Collaboration' ],
|
|
);
|
|
sub _sortOrder_options {
|
|
my $session = shift->session;
|
|
my $i18n = WebGUI::International->new($session,"Asset_Collaboration");
|
|
return {
|
|
asc => $i18n->get('ascending'),
|
|
desc => $i18n->get('descending'),
|
|
};
|
|
}
|
|
property sortBy => (
|
|
fieldType => "selectBox",
|
|
default => 'assetData.revisionDate',
|
|
tab => 'display',
|
|
options => \&_sortBy_options,
|
|
label => [ 'sort by', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'sort by description', 'Asset_Collaboration' ],
|
|
);
|
|
sub _sortBy_options {
|
|
my $self = shift;
|
|
my $session = $self->session;
|
|
my $i18n = WebGUI::International->new($session,"Asset_Collaboration");
|
|
tie my %sortByOptions, 'Tie::IxHash';
|
|
%sortByOptions = (
|
|
lineage => $i18n->get('sequence'),
|
|
"assetData.revisionDate" => $i18n->get('date updated'),
|
|
creationDate => $i18n->get('date submitted'),
|
|
title => $i18n->get('title'),
|
|
userDefined1 => $i18n->get('user defined 1'),
|
|
userDefined2 => $i18n->get('user defined 2'),
|
|
userDefined3 => $i18n->get('user defined 3'),
|
|
userDefined4 => $i18n->get('user defined 4'),
|
|
userDefined5 => $i18n->get('user defined 5'),
|
|
);
|
|
if ($self->_useKarma) {
|
|
$sortByOptions{karmaRank} = $i18n->get('karma rank');
|
|
}
|
|
return \%sortByOptions;
|
|
}
|
|
property notificationTemplateId => (
|
|
fieldType => "template",
|
|
namespace => "Collaboration/Notification",
|
|
default => 'PBtmpl0000000000000027',
|
|
tab => 'mail',
|
|
label => [ 'notification template', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'notification template description', 'Asset_Collaboration' ],
|
|
);
|
|
property searchTemplateId => (
|
|
fieldType => "template",
|
|
namespace => "Collaboration/Search",
|
|
default => 'PBtmpl0000000000000031',
|
|
tab => 'display',
|
|
label => [ 'search template', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'search template description', 'Asset_Collaboration' ],
|
|
);
|
|
property postFormTemplateId => (
|
|
fieldType => "template",
|
|
namespace => "Collaboration/PostForm",
|
|
default => 'PBtmpl0000000000000029',
|
|
tab => 'display',
|
|
label => [ 'post template', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'post template description', 'Asset_Collaboration' ],
|
|
);
|
|
property threadTemplateId => (
|
|
fieldType => "template",
|
|
namespace => "Collaboration/Thread",
|
|
default => 'PBtmpl0000000000000032',
|
|
tab => 'display',
|
|
label => [ 'thread template', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'thread template description', 'Asset_Collaboration' ],
|
|
);
|
|
property collaborationTemplateId => (
|
|
fieldType => "template",
|
|
namespace => 'Collaboration',
|
|
default => 'PBtmpl0000000000000026',
|
|
tab => 'display',
|
|
label => [ 'system template', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'system template description', 'Asset_Collaboration' ],
|
|
);
|
|
property karmaPerPost => (
|
|
fieldType => "integer",
|
|
default => 0,
|
|
tab => 'properties',
|
|
noFormPost => \&_disableForKarma,
|
|
label => [ 'karma/post', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'karma/post description', 'Asset_Collaboration' ],
|
|
);
|
|
sub _disableForKarma {
|
|
my $self = shift;
|
|
return ! $self->_useKarma;
|
|
}
|
|
property karmaSpentToRate => (
|
|
fieldType => "integer",
|
|
default => 0,
|
|
tab => 'properties',
|
|
noFormPost => \&_disableForKarma,
|
|
label => [ 'karma spent to rate', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'karma spent to rate description', 'Asset_Collaboration' ],
|
|
);
|
|
property karmaRatingMultiplier => (
|
|
fieldType => "integer",
|
|
default => 1,
|
|
tab => 'properties',
|
|
noFormPost => \&_disableForKarma,
|
|
label => [ 'karma rating multiplier', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'karma rating multiplier description', 'Asset_Collaboration' ],
|
|
);
|
|
property avatarsEnabled => (
|
|
fieldType => "yesNo",
|
|
default => 0,
|
|
tab => 'properties',
|
|
label => [ 'enable avatars', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'enable avatars description', 'Asset_Collaboration' ],
|
|
);
|
|
property enablePostMetaData => (
|
|
fieldType => "yesNo",
|
|
default => 0,
|
|
tab => 'meta',
|
|
label => [ 'enable metadata', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'enable metadata description', 'Asset_Collaboration' ],
|
|
);
|
|
property postGroupId => (
|
|
fieldType => "group",
|
|
default => '2',
|
|
tab => 'security',
|
|
label => [ 'who posts', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'who posts description', 'Asset_Collaboration' ],
|
|
);
|
|
property canStartThreadGroupId => (
|
|
fieldType => "group",
|
|
default => '2',
|
|
tab => 'security',
|
|
label => [ 'who threads', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'who threads description', 'Asset_Collaboration' ],
|
|
);
|
|
property defaultKarmaScale => (
|
|
fieldType => "integer",
|
|
default => 1,
|
|
tab => 'properties',
|
|
noFormPost => \&_disableForKarma,
|
|
label => [ "default karma scale", 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'default karma scale help', 'Asset_Collaboration' ],
|
|
);
|
|
property useCaptcha => (
|
|
fieldType => "yesNo",
|
|
default => '0',
|
|
tab => 'security',
|
|
label => [ 'use captcha label', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'use captcha hover help', 'Asset_Collaboration' ],
|
|
);
|
|
property subscriptionGroupId => (
|
|
fieldType => "subscriptionGroup",
|
|
tab => 'security',
|
|
label => [ "subscription group label", 'Asset_Collaboration' ],
|
|
hoverHelp => [ "subscription group hoverHelp", 'Asset_Collaboration' ],
|
|
noFormPost => 1,
|
|
default => undef,
|
|
);
|
|
property groupToEditPost => (
|
|
tab => "security",
|
|
label => [ 'group to edit label', 'Asset_Collaboration' ],
|
|
excludeGroups => [ 1, 7 ],
|
|
hoverHelp => [ 'group to edit hoverhelp', 'Asset_Collaboration' ],
|
|
uiLevel => 6,
|
|
fieldType => 'group',
|
|
builder => '_groupToEditPost_builder', # groupToEditPost should default to groupIdEdit
|
|
lazy => 1,
|
|
);
|
|
sub _groupToEditPost_builder {
|
|
my $session = shift->session;
|
|
my $groupIdEdit;
|
|
if($session->asset) {
|
|
$groupIdEdit = $session->asset->groupIdEdit;
|
|
}
|
|
else {
|
|
$groupIdEdit = '4';
|
|
}
|
|
return $groupIdEdit;
|
|
}
|
|
property postReceivedTemplateId => (
|
|
fieldType => 'template',
|
|
namespace => 'Collaboration/PostReceived',
|
|
tab => 'display',
|
|
label => [ 'post received template', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'post received template hoverHelp', 'Asset_Collaboration' ],
|
|
default => 'default_post_received1',
|
|
);
|
|
property unsubscribeTemplateId => (
|
|
fieldType => 'template',
|
|
namespace => 'Collaboration/Unsubscribe',
|
|
tab => 'display',
|
|
label => [ 'unsubscribe template', 'Asset_Collaboration' ],
|
|
hoverHelp => [ 'unsubscribe template hoverHelp', 'Asset_Collaboration' ],
|
|
default => 'default_CS_unsubscribe',
|
|
);
|
|
|
|
with 'WebGUI::Role::Asset::RssFeed';
|
|
|
|
use WebGUI::Group;
|
|
use WebGUI::HTML;
|
|
use WebGUI::International;
|
|
use WebGUI::Paginator;
|
|
use WebGUI::Asset::Wobject;
|
|
use WebGUI::Workflow::Cron;
|
|
|
|
#-------------------------------------------------------------------
|
|
sub _computePostCount {
|
|
my $self = shift;
|
|
return $self->getDescendantCount({
|
|
includeOnlyClasses => ['WebGUI::Asset::Post'],
|
|
statusToInclude => ['approved'],
|
|
});
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
sub _computeThreadCount {
|
|
my $self = shift;
|
|
return $self->getChildCount({
|
|
includeOnlyClasses => ['WebGUI::Asset::Post::Thread'],
|
|
statusToInclude => ['approved'],
|
|
});
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
# format the date according to rfc 822 (for RSS export)
|
|
my @_months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
|
|
sub _get_rfc822_date {
|
|
my $self = shift;
|
|
my ($time) = @_;
|
|
my ($year, $mon, $mday, $hour, $min, $sec) = $self->session->datetime->localtime($time);
|
|
my $month = $_months[$mon - 1];
|
|
return sprintf("%02d %s %04d %02d:%02d:%02d GMT",
|
|
$mday, $month, $year, $hour, $min, $sec);
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 _useKarma
|
|
|
|
Internal method for determining if the karma is enabled in settings.
|
|
|
|
=cut
|
|
|
|
sub _useKarma {
|
|
my $self = shift;
|
|
return $self->session->setting->get('useKarma');
|
|
}
|
|
#-------------------------------------------------------------------
|
|
sub _visitorCacheKey {
|
|
my $self = shift;
|
|
my $pn = $self->session->form->process('pn');
|
|
return "view_".$self->getId."?pn=".$pn;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
sub _visitorCacheOk {
|
|
my $self = shift;
|
|
return ($self->session->user->isVisitor
|
|
&& !$self->session->form->process('sortBy'));
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 appendPostListTemplateVars ($var, $p)
|
|
|
|
Takes a WebGUI::Paginator object that should be full of Posts, and appends template
|
|
variables to the hash reference.
|
|
|
|
=head3 $var
|
|
|
|
A hash reference. Template variables will be added to it.
|
|
|
|
=head3 $p
|
|
|
|
A reference to a WebGUI::Paginator object.
|
|
|
|
=cut
|
|
|
|
sub appendPostListTemplateVars {
|
|
my $self = shift;
|
|
my $session = $self->session;
|
|
my $var = shift;
|
|
my $p = shift;
|
|
my $page = $p->getPageData;
|
|
my $i = 0;
|
|
my ($icon, $datetime) = $session->quick(qw(icon datetime));
|
|
my $isVisitor = $session->user->isVisitor;
|
|
foreach my $row (@$page) {
|
|
my $post = WebGUI::Asset->newById($session,$row->{assetId}, $row->{revisionDate});
|
|
$post->{_parent} = $self; # caching parent for efficiency
|
|
my $controls = $icon->delete('func=delete',$post->url,"Delete") . $icon->edit('func=edit',$post->url);
|
|
if ($self->sortBy eq "lineage") {
|
|
if ($self->sortOrder eq "desc") {
|
|
$controls .= $icon->moveUp('func=demote',$post->url).$icon->moveDown('func=promote',$post->url);
|
|
}
|
|
else {
|
|
$controls .= $icon->moveUp('func=promote',$post->url).$icon->moveDown('func=demote',$post->url);
|
|
}
|
|
}
|
|
my @rating_loop;
|
|
for (my $i=0;$i<=$post->rating;$i++) {
|
|
push(@rating_loop,{'rating_loop.count'=>$i});
|
|
}
|
|
my %lastReply;
|
|
my $hasRead = 0;
|
|
if ($post->isa('WebGUI::Asset::Post::Thread')) {
|
|
if ($self->displayLastReply) {
|
|
my $lastPost = $post->getLastPost();
|
|
%lastReply = (
|
|
"lastReply.url" => $lastPost->getThreadLinkUrl,
|
|
"lastReply.title" => $lastPost->title,
|
|
"lastReply.user.isVisitor" => $lastPost->ownerUserId eq "1",
|
|
"lastReply.username" => $lastPost->username,
|
|
"lastReply.hideProfileUrl" => $lastPost->ownerUserId eq "1" || $isVisitor,
|
|
"lastReply.userProfile.url" => $lastPost->getPosterProfileUrl(),
|
|
"lastReply.dateSubmitted.human" => $datetime->epochToHuman($lastPost->creationDate,"%z"),
|
|
"lastReply.timeSubmitted.human" => $datetime->epochToHuman($lastPost->creationDate,"%Z"),
|
|
);
|
|
}
|
|
$hasRead = $post->isMarkedRead;
|
|
}
|
|
my %postVars = (
|
|
%{$post->get},
|
|
"id" => $post->getId,
|
|
"url" => $post->getThreadLinkUrl,
|
|
rating_loop => \@rating_loop,
|
|
"content" => $post->formatContent,
|
|
"status" => $post->getStatus,
|
|
"thumbnail" => $post->getThumbnailUrl,
|
|
"image.url" => $post->getImageUrl,
|
|
"dateSubmitted.human" => $datetime->epochToHuman($post->creationDate,"%z"),
|
|
"dateUpdated.human" => $datetime->epochToHuman($post->revisionDate,"%z"),
|
|
"timeSubmitted.human" => $datetime->epochToHuman($post->creationDate,"%Z"),
|
|
"timeUpdated.human" => $datetime->epochToHuman($post->revisionDate,"%Z"),
|
|
"hideProfileUrl" => $post->ownerUserId eq '1' || $isVisitor,
|
|
"userProfile.url" => $post->getPosterProfileUrl,
|
|
"user.isVisitor" => $post->ownerUserId eq "1",
|
|
"edit.url" => $post->getEditUrl,
|
|
'controls' => $controls,
|
|
"isSecond" => (($i+1) == 2),
|
|
"isThird" => (($i+1) == 3),
|
|
"isFourth" => (($i+1) == 4),
|
|
"isFifth" => (($i+1) == 5),
|
|
"user.hasRead" => $hasRead,
|
|
"user.isPoster" => $post->isPoster,
|
|
"avatar.url" => $post->getAvatarUrl,
|
|
%lastReply
|
|
);
|
|
$post->getTemplateMetadataVars(\%postVars);
|
|
if ($row->{className} =~ m/^WebGUI::Asset::Post::Thread/) {
|
|
$postVars{'rating'} = $post->threadRating;
|
|
}
|
|
push(@{$var->{post_loop}}, \%postVars );
|
|
$i++;
|
|
}
|
|
$p->appendTemplateVars($var);
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 appendTemplateLabels ($var)
|
|
|
|
Appends a whole mess of internationalized labels for use in a template.
|
|
|
|
=head3 $var
|
|
|
|
A hash reference. Template labels will be appended to it.
|
|
|
|
=cut
|
|
|
|
sub appendTemplateLabels {
|
|
my $self = shift;
|
|
my $var = shift;
|
|
my $i18n = WebGUI::International->new($self->session, "Asset_Collaboration");
|
|
$var->{"transferkarma.label"} = $i18n->get("transfer karma");
|
|
$var->{"karmaScale.label"} = $i18n->get("karma scale");
|
|
$var->{"close.label"} = $i18n->get("close");
|
|
$var->{"closed.label"} = $i18n->get("closed");
|
|
$var->{"open.label"} = $i18n->get("open");
|
|
$var->{"critical.label"} = $i18n->get("critical");
|
|
$var->{"cosmetic.label"} = $i18n->get("cosmetic");
|
|
$var->{"minor.label"} = $i18n->get("minor");
|
|
$var->{"fatal.label"} = $i18n->get("fatal");
|
|
$var->{"severity.label"} = $i18n->get("severity");
|
|
$var->{"add.label"} = $i18n->get("add");
|
|
$var->{"addlink.label"} = $i18n->get("addlink");
|
|
$var->{"addquestion.label"} = $i18n->get("addquestion");
|
|
$var->{'answer.label'} = $i18n->get("answer");
|
|
$var->{'attachment.label'} = $i18n->get("attachment");
|
|
$var->{'archive.label'} = $i18n->get("archive");
|
|
$var->{'unarchive.label'} = $i18n->get("unarchive");
|
|
$var->{"by.label"} = $i18n->get("by");
|
|
$var->{'body.label'} = $i18n->get("body");
|
|
$var->{"back.label"} = $i18n->get("back");
|
|
$var->{'compensation.label'} = $i18n->get("compensation");
|
|
$var->{'contentType.label'} = $i18n->get("contentType");
|
|
$var->{"date.label"} = $i18n->get("date");
|
|
$var->{"delete.label"} = $i18n->get("delete");
|
|
$var->{'description.label'} = $i18n->get("description");
|
|
$var->{"edit.label"} = $i18n->get("edit");
|
|
$var->{'image.label'} = $i18n->get("image");
|
|
$var->{"job.header.label"} = $i18n->get("edit job");
|
|
$var->{"job.title.label"} = $i18n->get("job title");
|
|
$var->{"job.description.label"} = $i18n->get("job description");
|
|
$var->{"job.requirements.label"} = $i18n->get("job requirements");
|
|
$var->{"karmaRank.label"} = $i18n->get("karma rank");
|
|
$var->{"location.label"} = $i18n->get("location");
|
|
$var->{"layout.flat.label"} = $i18n->get("flatLayout");
|
|
$var->{'link.header.label'} = $i18n->get("edit link");
|
|
$var->{"lastReply.label"} = $i18n->get("lastReply");
|
|
$var->{"lock.label"} = $i18n->get("lock");
|
|
$var->{"layout.label"} = $i18n->get("layout");
|
|
$var->{'message.header.label'} = $i18n->get("edit message");
|
|
$var->{'message.label'} = $i18n->get("message");
|
|
$var->{"next.label"} = $i18n->get("next");
|
|
$var->{'newWindow.label'} = $i18n->get("new window");
|
|
$var->{"layout.nested.label"} = $i18n->get("nested");
|
|
$var->{"previous.label"} = $i18n->get("previous");
|
|
$var->{"post.label"} = $i18n->get("post");
|
|
$var->{'question.label'} = $i18n->get("question");
|
|
$var->{'question.header.label'} = $i18n->get("edit question");
|
|
$var->{"rating.label"} = $i18n->get("rating");
|
|
$var->{"rate.label"} = $i18n->get("rate");
|
|
$var->{"reply.label"} = $i18n->get("reply");
|
|
$var->{"replies.label"} = $i18n->get("replies");
|
|
$var->{"readmore.label"} = $i18n->get("read more");
|
|
$var->{"responses.label"} = $i18n->get("responses");
|
|
$var->{"search.label"} = $i18n->get("search");
|
|
$var->{'subject.label'} = $i18n->get("subject");
|
|
$var->{"subscribe.label"} = $i18n->get("subscribe");
|
|
$var->{'submission.header.label'} = $i18n->get("edit submission");
|
|
$var->{"stick.label"} = $i18n->get("sticky");
|
|
$var->{"status.label"} = $i18n->get("status");
|
|
$var->{"synopsis.label"} = $i18n->get("synopsis");
|
|
$var->{"thumbnail.label"} = $i18n->get("thumbnail");
|
|
$var->{"title.label"} = $i18n->get("title");
|
|
$var->{"unlock.label"} = $i18n->get("unlock");
|
|
$var->{"unstick.label"} = $i18n->get("unstick");
|
|
$var->{"unsubscribe.label"} = $i18n->get("unsubscribe");
|
|
$var->{'url.label'} = $i18n->get("url");
|
|
$var->{"user.label"} = $i18n->get("user");
|
|
$var->{"views.label"} = $i18n->get("views");
|
|
$var->{'visitorName.label'} = $i18n->get("visitor");
|
|
$var->{"captcha_label"} = $i18n->get("captcha label");
|
|
$var->{'keywords.label'} = $i18n->get('keywords label');
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 canEdit ( [ $userId ] )
|
|
|
|
Extends the base method to include adding Threads to this CS.
|
|
|
|
=head3 $userId
|
|
|
|
A userId to check for edit permissions. If $userId is false, then it checks
|
|
the current session user.
|
|
|
|
=cut
|
|
|
|
around canEdit => sub {
|
|
my $orig = shift;
|
|
my $self = shift;
|
|
my $userId = shift || $self->session->user->userId;
|
|
return (
|
|
(
|
|
(
|
|
$self->session->form->process("func") eq "add" ||
|
|
(
|
|
$self->session->form->process("assetId") eq "new" &&
|
|
$self->session->form->process("func") eq "addSave" &&
|
|
$self->session->form->process("className") eq "WebGUI::Asset::Post::Thread"
|
|
)
|
|
) &&
|
|
$self->canStartThread( $userId )
|
|
) || # account for new threads
|
|
$self->$orig( $userId )
|
|
);
|
|
};
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 canModerate ( [ $userId ] )
|
|
|
|
Returns true if the user can edit this Collaboration System.
|
|
|
|
=head3 $userId
|
|
|
|
A userId to check for permission. If $userId is false, then it checks
|
|
the current session user.
|
|
|
|
=cut
|
|
|
|
sub canModerate {
|
|
my $self = shift;
|
|
my $userId = shift || $self->session->user->userId;
|
|
return $self->WebGUI::Asset::canEdit( $userId );
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 canPost ( [ $userId ] )
|
|
|
|
Returns true if the user can post to the CS. Checks that the CS is committed,
|
|
that the user is in the group to post, or that the user can edit this CS.
|
|
|
|
=head3 $userId
|
|
|
|
A userId to check for edit permissions. If $userId is false, then it checks
|
|
the current session user.
|
|
|
|
=cut
|
|
|
|
sub canPost {
|
|
my $self = shift;
|
|
my $userId = shift;
|
|
my $session = $self->session;
|
|
my $user = $userId
|
|
? WebGUI::User->new( $session, $userId )
|
|
: $self->session->user
|
|
;
|
|
|
|
# checks to make sure that the cs has been committed at least once
|
|
if ( $self->status ne "approved" && $self->getTagCount <= 1 ) {
|
|
return 0;
|
|
}
|
|
# Users in the postGroupId can post
|
|
elsif ( $user->isInGroup( $self->postGroupId ) ) {
|
|
return 1;
|
|
}
|
|
# Users who can edit the collab can post
|
|
else {
|
|
return $self->WebGUI::Asset::canEdit( $userId );
|
|
}
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 canSubscribe ( [ $userId ] )
|
|
|
|
Returns true if the user can subscribe to the CS. Checks that the user is registered
|
|
and that they canView the Post.
|
|
|
|
=head3 $userId
|
|
|
|
A userId to check for edit permissions. If $userId is false, then it checks
|
|
the current session user.
|
|
|
|
=cut
|
|
|
|
sub canSubscribe {
|
|
my $self = shift;
|
|
my $userId = shift;
|
|
my $session = $self->session;
|
|
my $user = $userId
|
|
? WebGUI::User->new( $session, $userId )
|
|
: $self->session->user
|
|
;
|
|
return ($user->isRegistered && $self->canView( $userId ) );
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 canStartThread ( [ $userId ] )
|
|
|
|
Returns true if the user can start a thread in the CS. Checks that the user is in the
|
|
canStartThreadGroup or that they canEdit the CS.
|
|
|
|
=head3 $userId
|
|
|
|
A userId to check for edit permissions. If $userId is false, then it checks
|
|
the current session user.
|
|
|
|
=cut
|
|
|
|
sub canStartThread {
|
|
my $self = shift;
|
|
my $userId = shift;
|
|
my $session = $self->session;
|
|
my $user = $userId
|
|
? WebGUI::User->new( $session, $userId )
|
|
: $self->session->user
|
|
;
|
|
return (
|
|
$user->isInGroup($self->canStartThreadGroupId)
|
|
|| $self->WebGUI::Asset::canEdit( $userId )
|
|
);
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 commit
|
|
|
|
Extend the base method to handle making a cron job for fetching mail for the CS. The
|
|
cron job is created even if the CS does not have email enabled. The cron is disabled
|
|
in that case.
|
|
|
|
=cut
|
|
|
|
override commit => sub {
|
|
my $self = shift;
|
|
super();
|
|
my $cron = undef;
|
|
if ($self->getMailCronId) {
|
|
$cron = WebGUI::Workflow::Cron->new($self->session, $self->getMailCronId);
|
|
}
|
|
my $i18n = WebGUI::International->new($self->session, "Asset_Collaboration");
|
|
unless (defined $cron) {
|
|
$cron = WebGUI::Workflow::Cron->create($self->session, {
|
|
title=>$self->getTitle." ".$i18n->get("mail"),
|
|
className=>(ref $self),
|
|
methodName=>"new",
|
|
parameters=>$self->getId,
|
|
workflowId=>"csworkflow000000000001",
|
|
$self->getCronIntervals,
|
|
});
|
|
$self->update({getMailCronId=>$cron->getId});
|
|
}
|
|
$cron->set({
|
|
enabled => $self->get('getMail') ? 1 : 0,
|
|
title => $self->getTitle." ".$i18n->get("mail"),
|
|
$self->getCronIntervals(),
|
|
});
|
|
};
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 createSubscriptionGroup
|
|
|
|
Creates a group to hold users who want to receive posts to this CS by email.
|
|
|
|
=cut
|
|
|
|
sub createSubscriptionGroup {
|
|
my $self = shift;
|
|
my $group = WebGUI::Group->new($self->session, "new");
|
|
$group->name($self->getId);
|
|
$group->description("The group to store subscriptions for the collaboration system ".$self->getId);
|
|
$group->isEditable(0);
|
|
$group->showInForms(0);
|
|
$group->deleteGroups([3]); # admins don't want to be auto subscribed to this thing
|
|
$self->update({
|
|
subscriptionGroupId=>$group->getId
|
|
});
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 duplicate
|
|
|
|
Extend the base method to handle making a subscription group for the new CS, and
|
|
to build a new Cron job. It also recalculates the number of threads and replies.
|
|
|
|
=cut
|
|
|
|
sub duplicate {
|
|
my $self = shift;
|
|
my $newAsset = $self->next::method(@_);
|
|
$newAsset->createSubscriptionGroup;
|
|
my $i18n = WebGUI::International->new($self->session, "Asset_Collaboration");
|
|
my $newCron = WebGUI::Workflow::Cron->create($self->session, {
|
|
title=>$self->getTitle." ".$i18n->get("mail"),
|
|
className=>(ref $self),
|
|
methodName=>"new",
|
|
parameters=>$self->getId,
|
|
workflowId=>"csworkflow000000000001",
|
|
$self->getCronIntervals(),
|
|
});
|
|
$newAsset->update({getMailCronId=>$newCron->getId});
|
|
$newAsset->incrementReplies('','');
|
|
return $newAsset;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 duplicateBranch.
|
|
|
|
Extend the base method to recalculate the number of threads and replies.
|
|
|
|
=cut
|
|
|
|
sub duplicateBranch {
|
|
my $self = shift;
|
|
my $newAsset = $self->next::method(@_);
|
|
$newAsset->incrementReplies('','');
|
|
return $newAsset;
|
|
}
|
|
|
|
#----------------------------------------------------------------------------
|
|
|
|
=head2 getCronIntervals
|
|
|
|
Translate the settings for getCsMailInterval into options for Spectre's Cron,
|
|
minuteOfHour, hourOfDay and so on.
|
|
|
|
Returns a hash of those options that can be folded into a hash of property settings for the
|
|
Cron job.
|
|
|
|
=cut
|
|
|
|
sub getCronIntervals {
|
|
my $self = shift;
|
|
my $interval = $self->get('getMailInterval');
|
|
##My kingdom for a switch statement!
|
|
if ($interval eq 'every minute') {
|
|
return(
|
|
hourOfDay => '*',
|
|
minuteOfHour => '*/1',
|
|
);
|
|
}
|
|
elsif ($interval eq 'every other minute') {
|
|
return(
|
|
hourOfDay => '*',
|
|
minuteOfHour => '*/2',
|
|
);
|
|
}
|
|
elsif ($interval eq 'every 5 minutes') {
|
|
return(
|
|
hourOfDay => '*',
|
|
minuteOfHour => '*/5',
|
|
);
|
|
}
|
|
elsif ($interval eq 'every 10 minutes') {
|
|
return(
|
|
hourOfDay => '*',
|
|
minuteOfHour => '*/10',
|
|
);
|
|
}
|
|
elsif ($interval eq 'every 15 minutes') {
|
|
return(
|
|
hourOfDay => '*',
|
|
minuteOfHour => '*/15',
|
|
);
|
|
}
|
|
elsif ($interval eq 'every 20 minutes') {
|
|
return(
|
|
hourOfDay => '*',
|
|
minuteOfHour => '*/20',
|
|
);
|
|
}
|
|
elsif ($interval eq 'every 30 minutes') {
|
|
return(
|
|
hourOfDay => '*',
|
|
minuteOfHour => '*/30',
|
|
);
|
|
}
|
|
elsif ($interval eq 'every hour') {
|
|
return(
|
|
hourOfDay => '*',
|
|
minuteOfHour => '0',
|
|
);
|
|
}
|
|
elsif ($interval eq 'every other hour') {
|
|
return(
|
|
hourOfDay => '*/2',
|
|
minuteOfHour => '0',
|
|
);
|
|
}
|
|
elsif ($interval eq 'once per day') {
|
|
return(
|
|
hourOfDay => '7',
|
|
minuteOfHour => '0',
|
|
);
|
|
}
|
|
return(
|
|
minuteOfHour => '*/10',
|
|
);
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getHelpers ( )
|
|
|
|
Add the collaboration-specific asset helpers
|
|
|
|
=cut
|
|
|
|
override getHelpers => sub {
|
|
my ( $self ) = @_;
|
|
my $helpers = super();
|
|
|
|
my $i18n = WebGUI::International->new($self->session, 'Asset_Collaboration');
|
|
$helpers->{ unarchiveAll } = {
|
|
label => $i18n->get("unarchive all"),
|
|
url => $self->getUrl( 'func=unarchiveAll' ),
|
|
confirm => $i18n->get("unarchive confirm"),
|
|
};
|
|
|
|
return $helpers;
|
|
};
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getNewThreadUrl( )
|
|
|
|
Formats the url to start a new thread.
|
|
|
|
=cut
|
|
|
|
sub getNewThreadUrl {
|
|
my $self = shift;
|
|
$self->getUrl("func=add;className=WebGUI::Asset::Post::Thread");
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getRssFeedItems
|
|
|
|
Returns an array ref of Posts for use in making the feeds for this CS.
|
|
|
|
=cut
|
|
|
|
sub getRssFeedItems {
|
|
my $self = shift;
|
|
|
|
# XXX copied and reformatted this query from www_viewRSS, but why is it constructed like this?
|
|
# And it's duplicated inside view, too! Eeeagh! And it uses the versionTag scratch var...
|
|
my ($sortBy, $sortOrder) = ($self->sortBy, $self->sortOrder);
|
|
|
|
my @postIds = $self->session->db->buildArray(<<"SQL", [$self->getId, $self->session->scratch->get('versionTag')]);
|
|
SELECT asset.assetId
|
|
FROM Thread
|
|
LEFT JOIN asset ON Thread.assetId = asset.assetId
|
|
LEFT JOIN Post ON Post.assetId = Thread.assetId AND Post.revisionDate = Thread.revisionDate
|
|
LEFT JOIN assetData ON assetData.assetId = Thread.assetId
|
|
AND assetData.revisionDate = Thread.revisionDate
|
|
WHERE asset.parentId = ? AND asset.state = 'published' AND asset.className = 'WebGUI::Asset::Post::Thread'
|
|
AND (assetData.status = 'approved' OR assetData.tagId = ?)
|
|
GROUP BY assetData.assetId
|
|
ORDER BY $sortBy $sortOrder
|
|
SQL
|
|
my $siteUrl = $self->session->url->getSiteURL();
|
|
my $datetime = $self->session->datetime;
|
|
|
|
my @posts;
|
|
my $rssLimit = $self->itemsPerFeed;
|
|
for my $postId (@postIds) {
|
|
my $post = WebGUI::Asset->newById($self->session, $postId);
|
|
my $postUrl = $siteUrl . $post->getUrl;
|
|
# Buggo: this is an abuse of 'author'. 'author' is supposed to be an email address.
|
|
# But this is how it was in the original Collaboration RSS, so.
|
|
|
|
# Create the attachment template loop
|
|
my $storage = $post->getStorageLocation;
|
|
my $attachmentLoop = [];
|
|
if ($post->storageId) {
|
|
for my $file (@{$storage->getFiles}) {
|
|
push @{$attachmentLoop}, {
|
|
'attachment.url' => $storage->getUrl($file),
|
|
'attachment.path' => $storage->getPath($file),
|
|
'attachment_thumbnail' => $storage->getThumbnailUrl($file),
|
|
'attachment.length' => $storage->getFileSize($file),
|
|
};
|
|
}
|
|
}
|
|
|
|
push @posts, {
|
|
author => $post->username,
|
|
title => $post->title,
|
|
'link' => $postUrl,
|
|
guid => $postUrl,
|
|
description => $post->synopsis,
|
|
epochDate => $post->creationDate,
|
|
pubDate => $datetime->epochToMail($post->creationDate),
|
|
attachmentLoop => $attachmentLoop,
|
|
userDefined1 => $post->userDefined1,
|
|
userDefined2 => $post->userDefined2,
|
|
userDefined3 => $post->userDefined3,
|
|
userDefined4 => $post->userDefined4,
|
|
userDefined5 => $post->userDefined5,
|
|
};
|
|
|
|
last if $rssLimit <= scalar(@posts);
|
|
}
|
|
|
|
return \@posts;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getSearchUrl ( )
|
|
|
|
Formats the url to the forum search engine.
|
|
|
|
=cut
|
|
|
|
sub getSearchUrl {
|
|
my $self = shift;
|
|
return $self->getUrl("func=search");
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getSortByUrl ( sortBy )
|
|
|
|
Formats the url to change the default sort.
|
|
|
|
=head3 sortBy
|
|
|
|
The sort by string. Can be views, rating, date replies, or lastreply.
|
|
|
|
=cut
|
|
|
|
sub getSortByUrl {
|
|
my $self = shift;
|
|
my $sortBy = shift;
|
|
return $self->getUrl("sortBy=".$sortBy);
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getSortBy
|
|
|
|
Retrieves the field to sort by
|
|
|
|
=cut
|
|
|
|
sub getSortBy {
|
|
my $self = shift;
|
|
my $scratchSortBy = $self->getId."_sortBy";
|
|
my $sortBy = $self->session->scratch->get($scratchSortBy) || $self->sortBy;
|
|
# XXX: This should be fixed in an upgrade and in the definition, NOT HERE
|
|
if ( $sortBy eq "rating" ) {
|
|
$sortBy = "threadRating";
|
|
}
|
|
return $sortBy;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getSortOrder
|
|
|
|
Retrieves the direction to sort in
|
|
|
|
=cut
|
|
|
|
sub getSortOrder {
|
|
my $self = shift;
|
|
my $scratchSortOrder = $self->getId."_sortDir";
|
|
my $sortOrder = $self->session->scratch->get($scratchSortOrder) || $self->sortOrder;
|
|
return $sortOrder;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getSubscribeUrl ( )
|
|
|
|
Formats the url to subscribe to the forum.
|
|
|
|
=cut
|
|
|
|
sub getSubscribeUrl {
|
|
my $self = shift;
|
|
return $self->getUrl("func=subscribe");
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getThreadsPaginator
|
|
|
|
Returns a WebGUI::Paginator object containing all the threads in this
|
|
Collaboration System
|
|
|
|
=cut
|
|
|
|
sub getThreadsPaginator {
|
|
my $self = shift;
|
|
my $session = $self->session;
|
|
|
|
my $scratchSortBy = $self->getId."_sortBy";
|
|
my $scratchSortOrder = $self->getId."_sortDir";
|
|
my $sortBy = $self->session->form->process("sortBy")
|
|
|| $self->session->scratch->get($scratchSortBy)
|
|
|| $self->sortBy;
|
|
$sortBy =~ s/^\w+\.//;
|
|
# Sort by the thread rating instead of the post rating. other places don't care about threads.
|
|
$sortBy = $sortBy eq 'rating' ? 'threadRating' : $sortBy;
|
|
if (! ($sortBy ~~ [qw/userDefined1 userDefined2 userDefined3 userDefined4 userDefined5 title lineage revisionDate creationDate karmaRank threadRating views replies lastPostDate/])) {
|
|
$sortBy = 'revisionDate';
|
|
}
|
|
if ($sortBy eq 'assetId' || $sortBy eq 'revisionDate') {
|
|
$sortBy = 'assetData.' . $sortBy;
|
|
}
|
|
my $sortOrder = $self->session->form->process("sortOrder")
|
|
|| $self->session->scratch->get($scratchSortOrder)
|
|
|| $self->get("sortOrder");
|
|
#$sortOrder = lc $sortOrder;
|
|
#$sortOrder = 'desc' if ($sortOrder ne 'asc' && $sortOrder ne 'desc');
|
|
if ($sortBy ne $self->session->scratch->get($scratchSortBy) && $self->session->form->process("func") ne "editSave") {
|
|
$self->session->scratch->set($scratchSortBy,$self->session->form->process("sortBy"));
|
|
$self->session->scratch->set($scratchSortOrder, $sortOrder);
|
|
}
|
|
elsif ($self->session->form->process("sortBy") && $self->session->form->process("func") ne "editSave" && ! $self->session->form->process('sortOrder')) {
|
|
if ($sortOrder eq "asc") {
|
|
$sortOrder = "desc";
|
|
}
|
|
else {
|
|
$sortOrder = "asc";
|
|
}
|
|
$self->session->scratch->set($scratchSortOrder, $sortOrder);
|
|
}
|
|
$sortBy = join('.', map { $self->session->db->quote_identifier($_) } split(/\./, $sortBy));
|
|
$sortOrder ||= 'desc';
|
|
|
|
my $sql = "
|
|
select
|
|
asset.assetId,
|
|
asset.className,
|
|
assetData.revisionDate as revisionDate
|
|
from Thread
|
|
left join asset on Thread.assetId=asset.assetId
|
|
left join Post on Post.assetId=Thread.assetId and Thread.revisionDate = Post.revisionDate
|
|
left join assetData on assetData.assetId=Thread.assetId and Thread.revisionDate = assetData.revisionDate
|
|
where
|
|
asset.parentId=".$self->session->db->quote($self->getId)."
|
|
and asset.state='published'
|
|
and asset.className='WebGUI::Asset::Post::Thread'
|
|
and assetData.revisionDate=(
|
|
select
|
|
max(revisionDate)
|
|
from
|
|
assetData
|
|
where
|
|
assetData.assetId=asset.assetId
|
|
and (status='approved' or status='archived')
|
|
)
|
|
and status='approved'
|
|
group by
|
|
assetData.assetId
|
|
order by
|
|
Thread.isSticky desc,
|
|
".$sortBy."
|
|
".$sortOrder;
|
|
my $p = WebGUI::Paginator->new($session,$self->getUrl,$self->threadsPerPage);
|
|
$p->setDataByQuery($sql);
|
|
|
|
return $p;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getUnsubscribeUrl ( )
|
|
|
|
Formats the url to unsubscribe from the forum.
|
|
|
|
=cut
|
|
|
|
sub getUnsubscribeUrl {
|
|
my $self = shift;
|
|
return $self->getUrl("func=unsubscribe");
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getViewTemplateVars
|
|
|
|
Returns a hash reference full of template variables that are used in
|
|
several CS templates.
|
|
|
|
=cut
|
|
|
|
sub getViewTemplateVars {
|
|
my $self = shift;
|
|
my %var;
|
|
$var{'user.canPost'} = $self->canPost;
|
|
$var{'user.canStartThread'} = $self->canStartThread;
|
|
$var{"add.url"} = $self->getNewThreadUrl;
|
|
$var{"rss.url"} = $self->getRssFeedUrl;
|
|
$var{'user.isModerator'} = $self->canModerate;
|
|
$var{'user.isVisitor'} = ($self->session->user->isVisitor);
|
|
$var{'user.isSubscribed'} = $self->isSubscribed;
|
|
$var{'sortby.title.url'} = $self->getSortByUrl("title");
|
|
$var{'sortby.username.url'} = $self->getSortByUrl("username");
|
|
$var{'karmaIsEnabled'} = $self->session->setting->get("useKarma");
|
|
$var{'sortby.karmaRank.url'} = $self->getSortByUrl("karmaRank");
|
|
$var{'sortby.date.url'} = $self->getSortByUrl("creationDate");
|
|
$var{'sortby.lastreply.url'} = $self->getSortByUrl("lastPostDate");
|
|
$var{'sortby.views.url'} = $self->getSortByUrl("views");
|
|
$var{'sortby.replies.url'} = $self->getSortByUrl("replies");
|
|
$var{'sortby.rating.url'} = $self->getSortByUrl("rating");
|
|
$var{"search.url"} = $self->getSearchUrl;
|
|
$var{"subscribe.url"} = $self->getSubscribeUrl;
|
|
$var{"unsubscribe.url"} = $self->getUnsubscribeUrl;
|
|
$var{"collaborationAssetId"} = $self->getId;
|
|
|
|
# Get the threads in this CS
|
|
my $p = $self->getThreadsPaginator;
|
|
$self->appendPostListTemplateVars(\%var, $p);
|
|
$self->appendTemplateLabels(\%var);
|
|
|
|
return \%var;
|
|
}
|
|
|
|
#--------------------------------------------------------------------------
|
|
|
|
=head2 groupIdView ( [newvalue] )
|
|
|
|
Override the existing accessor to update the subscription group if the value
|
|
changes.
|
|
|
|
=cut
|
|
|
|
around groupIdView => sub {
|
|
my $orig = shift;
|
|
my $self = shift;
|
|
my ( $newValue ) = @_;
|
|
my $oldValue = $self->$orig;
|
|
my $return = $self->$orig(@_);
|
|
# Update the subscription group so if they can't see the collab, they don't get e-mailed
|
|
if ( $newValue && $newValue ne $oldValue ) {
|
|
my $instance_data = {
|
|
workflowId => 'xR-_GRRbjBojgLsFx3dEMA',
|
|
className => 'WebGUI::Asset',
|
|
methodName => 'newPending',
|
|
parameters => $self->getId,
|
|
};
|
|
my $instance = WebGUI::Workflow::Instance->create($self->session, $instance_data);
|
|
$instance->start('skipRealtime');
|
|
}
|
|
return $return;
|
|
};
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 incrementReplies ( lastPostDate, lastPostId )
|
|
|
|
Increments the reply counter for this forum.
|
|
|
|
=head3 lastPostDate
|
|
|
|
The date of the post being added.
|
|
|
|
=head3 lastPostId
|
|
|
|
The unique identifier of the post being added.
|
|
|
|
=cut
|
|
|
|
sub incrementReplies {
|
|
my ($self, $lastPostDate, $lastPostId) = @_;
|
|
my $threads = $self->_computeThreadCount;
|
|
my $replies = $self->_computePostCount;
|
|
$self->update({replies=>$replies, threads=>$threads, lastPostId=>$lastPostId, lastPostDate=>$lastPostDate});
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 incrementThreads ( lastPostDate, lastPostId )
|
|
|
|
Increments the thread counter for this forum.
|
|
|
|
=head3 lastPostDate
|
|
|
|
The date of the post that was just added.
|
|
|
|
=head3 lastPostId
|
|
|
|
The unique identifier of the post that was just added.
|
|
|
|
=cut
|
|
|
|
sub incrementThreads {
|
|
my ($self, $lastPostDate, $lastPostId) = @_;
|
|
$self->update({threads=>$self->_computeThreadCount, lastPostId=>$lastPostId, lastPostDate=>$lastPostDate});
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 incrementViews ( )
|
|
|
|
Increments the views counter on this forum.
|
|
|
|
=cut
|
|
|
|
sub incrementViews {
|
|
my ($self) = @_;
|
|
$self->update({views=>$self->views+1});
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 isSubscribed ( )
|
|
|
|
Returns a boolean indicating whether the user is subscribed to the forum.
|
|
|
|
=cut
|
|
|
|
sub isSubscribed {
|
|
my $self = shift;
|
|
return $self->session->user->isInGroup($self->subscriptionGroupId);
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 prepareView ( )
|
|
|
|
See WebGUI::Asset::prepareView() for details.
|
|
|
|
=cut
|
|
|
|
sub prepareView {
|
|
my $self = shift;
|
|
$self->next::method;
|
|
my $template = WebGUI::Asset::Template->newById($self->session, $self->collaborationTemplateId);
|
|
if (!$template) {
|
|
WebGUI::Error::ObjectNotFound::Template->throw(
|
|
error => qq{Template not found},
|
|
templateId => $self->collaborationTemplateId,
|
|
assetId => $self->getId,
|
|
);
|
|
}
|
|
$template->prepare($self->getMetaDataAsTemplateVariables);
|
|
$self->{_viewTemplate} = $template;
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 processEditForm
|
|
|
|
Extend the base method to handle creating subscription groups, propagating
|
|
group privileges to all descendants and clearing scratch variables for sort key
|
|
and direction.
|
|
|
|
=cut
|
|
|
|
sub processEditForm {
|
|
my $self = shift;
|
|
my $updatePrivs = ($self->session->form->process("groupIdView") ne $self->groupIdView || $self->session->form->process("groupIdEdit") ne $self->groupIdEdit);
|
|
$self->next::method;
|
|
if ($self->subscriptionGroupId eq "") {
|
|
$self->createSubscriptionGroup;
|
|
}
|
|
if ($updatePrivs) {
|
|
my $descendantIter = $self->getLineageIterator(['descendants']);
|
|
while ( 1 ) {
|
|
my $descendant;
|
|
eval { $descendant = $descendantIter->() };
|
|
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
|
$self->session->log->error($x->full_message);
|
|
next;
|
|
}
|
|
last unless $descendant;
|
|
$descendant->update({
|
|
groupIdView=>$self->groupIdView,
|
|
groupIdEdit=>$self->groupIdEdit
|
|
});
|
|
}
|
|
}
|
|
$self->session->scratch->delete($self->getId."_sortBy");
|
|
$self->session->scratch->delete($self->getId."_sortDir");
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 purge
|
|
|
|
Extend the base method to delete the subscription group and cron job for emails.
|
|
|
|
=cut
|
|
|
|
override purge => sub {
|
|
my $self = shift;
|
|
my $group = WebGUI::Group->new($self->session, $self->subscriptionGroupId);
|
|
if ($group) {
|
|
$group->delete;
|
|
}
|
|
if ($self->getMailCronId) {
|
|
my $cron = WebGUI::Workflow::Cron->new($self->session, $self->getMailCronId);
|
|
$cron->delete if defined $cron;
|
|
}
|
|
super();
|
|
};
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 purgeCache ( )
|
|
|
|
Extend the base method to delete view and visitor caches.
|
|
|
|
=cut
|
|
|
|
override purgeCache => sub {
|
|
my $self = shift;
|
|
my $cache = $self->session->cache;
|
|
eval {
|
|
$cache->remove("view_".$self->getId);
|
|
$cache->remove($self->_visitorCacheKey);
|
|
};
|
|
super();
|
|
};
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 recalculateRating ( )
|
|
|
|
Calculates the rating of this forum from its threads and stores the new value in the forum properties.
|
|
|
|
=cut
|
|
|
|
sub recalculateRating {
|
|
my $self = shift;
|
|
|
|
# Get the number of threads
|
|
my ($count)
|
|
= $self->session->db->quickArray(
|
|
"select count(*) from Thread
|
|
left join asset on Thread.assetId=asset.assetId
|
|
left join Post on Thread.assetId=Post.assetId
|
|
AND Thread.revisionDate = (SELECT MAX(revisionDate) FROM Thread t WHERE t.assetId=asset.assetId)
|
|
where asset.parentId=?",
|
|
[$self->getId]
|
|
);
|
|
$count = $count || 1;
|
|
|
|
# Get the ratings of all the threads
|
|
my ($sum)
|
|
= $self->session->db->quickArray(
|
|
"SELECT SUM(Thread.threadRating)
|
|
FROM Thread
|
|
LEFT JOIN asset ON Thread.assetId=asset.assetId
|
|
LEFT JOIN Post ON Thread.assetId=Post.assetId
|
|
AND Thread.revisionDate = (SELECT MAX(revisionDate) FROM Thread t WHERE t.assetId=asset.assetId)
|
|
WHERE asset.parentId=?",
|
|
[$self->getId]
|
|
);
|
|
|
|
my $average = sprintf('%.0f', $sum/$count);
|
|
$self->update({rating=>$average});
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 setLastPost ( id, date )
|
|
|
|
Sets the most recent post in this collaboration system.
|
|
|
|
=head3 id
|
|
|
|
The assetId of the most recent post.
|
|
|
|
=head3 date
|
|
|
|
The date of the most recent post.
|
|
|
|
=cut
|
|
|
|
sub setLastPost {
|
|
my $self = shift;
|
|
my $id = shift;
|
|
my $date = shift;
|
|
$self->update({lastPostId=>$id, lastPostDate=>$date});
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 sumReplies ( )
|
|
|
|
Calculates the number of replies to this collaboration system and updates the counter to reflect that. Also updates thread count since it needs to know that to calculate reply count.
|
|
|
|
=cut
|
|
|
|
sub sumReplies {
|
|
my $self = shift;
|
|
my $threads = $self->_computeThreadCount;
|
|
my $replies = $self->_computePostCount;
|
|
$self->update({replies=>$replies, threads=>$threads});
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 sumThreads ( )
|
|
|
|
Calculates the number of threads in this collaboration system and updates the counter to reflect that.
|
|
|
|
=cut
|
|
|
|
sub sumThreads {
|
|
my $self = shift;
|
|
$self->update({threads=>$self->_computeThreadCount});
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 subscribe ( )
|
|
|
|
Subscribes a user to this collaboration system.
|
|
|
|
=cut
|
|
|
|
sub subscribe {
|
|
my $self = shift;
|
|
my $group;
|
|
my $subscriptionGroup = $self->subscriptionGroupId;
|
|
if ($subscriptionGroup) {
|
|
$group = WebGUI::Group->new($self->session,$subscriptionGroup);
|
|
}
|
|
if (!$group) {
|
|
$self->createSubscriptionGroup;
|
|
$group = WebGUI::Group->new($self->session,$self->subscriptionGroupId);
|
|
}
|
|
$group->addUsers([$self->session->user->userId]);
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 unsubscribe ( [$user] )
|
|
|
|
Unsubscribes a user from this collaboration system
|
|
|
|
=head3 $user
|
|
|
|
An optional user object to unsubscribe. If the object isn't passed, then it uses the session user.
|
|
|
|
=cut
|
|
|
|
sub unsubscribe {
|
|
my $self = shift;
|
|
my $user = shift || $self->session->user;
|
|
my $group = WebGUI::Group->new($self->session,$self->subscriptionGroupId);
|
|
return unless $group;
|
|
$group->deleteUsers([$user->userId]);
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 view
|
|
|
|
Render the CS, and handle local caching.
|
|
|
|
=cut
|
|
|
|
sub view {
|
|
my $self = shift;
|
|
my $cache = $self->session->cache;
|
|
if ($self->_visitorCacheOk) {
|
|
my $out = $cache->get($self->_visitorCacheKey);
|
|
$self->session->log->debug("HIT") if $out;
|
|
return $out if $out;
|
|
}
|
|
|
|
# If the asset is not called through the normal prepareView/view cycle, first call prepareView.
|
|
# This happens for instance in the viewDetail method in the Matrix. In that case the Collaboration
|
|
# is called through the api.
|
|
$self->prepareView unless ($self->{_viewTemplate});
|
|
my $out = $self->processTemplate($self->getViewTemplateVars,undef,$self->{_viewTemplate});
|
|
if ($self->_visitorCacheOk) {
|
|
$cache->set($self->_visitorCacheKey, $out, $self->visitorCacheTimeout);
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_search ( )
|
|
|
|
The web method to display and use the forum search interface.
|
|
|
|
=cut
|
|
|
|
sub www_search {
|
|
my $self = shift;
|
|
my $session = $self->session;
|
|
my $i18n = WebGUI::International->new($session, 'Asset_Collaboration');
|
|
my $var = {};
|
|
|
|
my $query = $self->session->form->process("query","text");
|
|
$var->{'form.header'} = WebGUI::Form::formHeader($self->session,{
|
|
action=> $self->getUrl("func=search;doit=1"),
|
|
method=> 'GET',
|
|
});
|
|
$var->{'query.form'} = WebGUI::Form::text($self->session,{
|
|
name => 'query',
|
|
value => $query
|
|
});
|
|
$var->{'form.search'} = WebGUI::Form::submit($self->session,{
|
|
value => $i18n->get(170,'WebGUI')
|
|
});
|
|
$var->{'form.footer'} = WebGUI::Form::formFooter($self->session);
|
|
$var->{'back.url' } = $self->getUrl;
|
|
|
|
$self->appendTemplateLabels($var);
|
|
$var->{'doit' } = $self->session->form->process("doit");
|
|
if ($self->session->form->process("doit")) {
|
|
my $search = WebGUI::Search->new($self->session);
|
|
$search->search({
|
|
keywords=>$query,
|
|
lineage=>[$self->lineage],
|
|
classes=>["WebGUI::Asset::Post", "WebGUI::Asset::Post::Thread"]
|
|
});
|
|
my $p = $search->getPaginatorResultSet($self->getUrl("func=search;doit=1;query=".$query), $self->threadsPerPage);
|
|
$self->appendPostListTemplateVars($var, $p);
|
|
}
|
|
return $self->processStyle($self->processTemplate($var, $self->searchTemplateId));
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_subscribe ( )
|
|
|
|
The web method to subscribe to a collaboration.
|
|
|
|
=cut
|
|
|
|
sub www_subscribe {
|
|
my $self = shift;
|
|
$self->subscribe if $self->canSubscribe;
|
|
return $self->www_view;
|
|
}
|
|
|
|
#----------------------------------------------------------------------------
|
|
|
|
=head2 www_unarchiveAll ( )
|
|
|
|
Unarchive all the threads in this collaboration system
|
|
|
|
=cut
|
|
|
|
sub www_unarchiveAll {
|
|
my ( $self ) = @_;
|
|
my $session = $self->session;
|
|
return $session->privilege->insufficient() unless $self->canEdit;
|
|
my $pb = WebGUI::ProgressBar->new($session);
|
|
my $i18n = WebGUI::International->new($session, 'Asset_Collaboration');
|
|
$pb->start($i18n->get('unarchive all'), $self->getUrl('func=edit'));
|
|
my $threadIter = $self->getLineageIterator(['children'],{
|
|
includeOnlyClasses => [ 'WebGUI::Asset::Post::Thread' ],
|
|
statusToInclude => [ 'archived' ],
|
|
} );
|
|
ASSET: while ( 1 ) {
|
|
my $thread;
|
|
eval { $thread = $threadIter->() };
|
|
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
|
|
$session->log->error($x->full_message);
|
|
next;
|
|
}
|
|
last unless $thread;
|
|
if ($thread->canEdit) {
|
|
$thread->unarchive;
|
|
}
|
|
}
|
|
return $pb->finish( $self->getUrl('func=edit') );
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_unsubscribe ( [$message] )
|
|
|
|
The web method to unsubscribe from a collaboration.
|
|
|
|
=head3 $message
|
|
|
|
An error message to display to the user.
|
|
|
|
=cut
|
|
|
|
sub www_unsubscribe {
|
|
my $self = shift;
|
|
my $message = shift;
|
|
if($self->canSubscribe){
|
|
$self->unsubscribe;
|
|
return $self->www_view;
|
|
}
|
|
else {
|
|
my $session = $self->session;
|
|
my $i18n = WebGUI::International->new($session, 'Asset_Collaboration');
|
|
my $var = $self->get();
|
|
$var->{title} = $self->getTitle;
|
|
$var->{url} = $self->getUrl;
|
|
$var->{formHeader} = WebGUI::Form::formHeader($session)
|
|
. WebGUI::Form::hidden($session, { name => 'func', value => 'unsubscribeConfirm', }, ),
|
|
$var->{formFooter} = WebGUI::Form::formFooter($session),
|
|
$var->{formSubmit} = WebGUI::Form::submit($session, { value => $i18n->get('unsubscribe'), }),
|
|
$var->{formEmail} = WebGUI::Form::email($session, { name => 'userEmail', value => $session->form->process('userEmail'), }),
|
|
$var->{formMessage} = $message;
|
|
return $self->processStyle($self->processTemplate($var, $self->get("unsubscribeTemplateId")));
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_unsubscribeConfirm ( )
|
|
|
|
Process the unsubscribe form.
|
|
|
|
=cut
|
|
|
|
sub www_unsubscribeConfirm {
|
|
my $self = shift;
|
|
my $session = $self->session;
|
|
return $self->www_view unless $session->form->validToken;
|
|
my $email = $session->form->process('userEmail', 'email');
|
|
return $self->www_view unless $email;
|
|
my $user = WebGUI::User->newByEmail($session, $email);
|
|
my $i18n = WebGUI::International->new($session, 'Asset_Collaboration');
|
|
if (! $user) {
|
|
return $self->www_unsubscribe($i18n->get('no user email error message'));
|
|
}
|
|
$self->unsubscribe($user);
|
|
return $self->www_unsubscribe($i18n->get('You have been unsubscribed'));
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_view
|
|
|
|
Extend the base method to handle the visitor cache timeout.
|
|
|
|
=cut
|
|
|
|
sub www_view {
|
|
my $self = shift;
|
|
my $disableCache = ($self->session->form->process("sortBy") ne "");
|
|
$self->session->response->setCacheControl($self->visitorCacheTimeout) if ($self->session->user->isVisitor && !$disableCache);
|
|
return $self->next::method(@_);
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_viewRSS ( )
|
|
|
|
Deprecated. Use www_viewRss() instead.
|
|
|
|
=cut
|
|
|
|
sub www_viewRSS {
|
|
my $self = shift;
|
|
return $self->www_viewRss;
|
|
}
|
|
|
|
__PACKAGE__->meta->make_immutable;
|
|
1;
|
|
|