belong. This allows chained method calls to "getMyParent", getParent, getWiki, getCalendar, etc. to work. Adds the new canPaste and validParent method to Asset and AssetClipboard.
1211 lines
32 KiB
Perl
1211 lines
32 KiB
Perl
package WebGUI::Asset::Post::Thread;
|
|
|
|
#-------------------------------------------------------------------
|
|
# WebGUI is Copyright 2001-2008 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 WebGUI::Asset::Template;
|
|
use WebGUI::Asset::Post;
|
|
use WebGUI::Cache;
|
|
use WebGUI::Group;
|
|
use WebGUI::International;
|
|
use WebGUI::Paginator;
|
|
use WebGUI::SQL;
|
|
use WebGUI::Utility;
|
|
|
|
our @ISA = qw(WebGUI::Asset::Post);
|
|
|
|
#-------------------------------------------------------------------
|
|
sub addRevision {
|
|
my $self = shift;
|
|
my $newSelf = $self->SUPER::addRevision(@_);
|
|
$newSelf->createSubscriptionGroup;
|
|
return $newSelf;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
sub archive {
|
|
my $self = shift;
|
|
foreach my $post (@{$self->getPosts}) {
|
|
$post->setStatusArchived;
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
sub canAdd {
|
|
my $class = shift;
|
|
my $session = shift;
|
|
return $session->user->isInGroup($session->asset->get('canStartThreadGroupId'));
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
sub canReply {
|
|
my $self = shift;
|
|
my $userId = shift || $self->session->user->userId;
|
|
return !$self->isThreadLocked
|
|
&& $self->getParent->get("allowReplies")
|
|
&& $self->getParent->canPost( $userId )
|
|
;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
sub canSubscribe {
|
|
my $self = shift;
|
|
my $userId = shift || $self->session->user->userId;
|
|
return ($userId ne "1" && $self->canView( $userId ) );
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
sub commit {
|
|
my $self = shift;
|
|
$self->SUPER::commit;
|
|
if ($self->isNew) {
|
|
$self->getParent->incrementThreads($self->get("revisionDate"),$self->getId);
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
# Override duplicateBranch here so that new posts get their threadId set correctly.
|
|
# Buggo: should this be part of the addRevision override instead?
|
|
|
|
sub duplicateBranch {
|
|
my $self = shift;
|
|
my $newAsset = $self->SUPER::duplicateBranch(@_);
|
|
|
|
foreach my $post (@{$newAsset->getPosts}) {
|
|
$post->rethreadUnder($newAsset);
|
|
}
|
|
$newAsset->normalizeLastPost;
|
|
|
|
return $newAsset;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
sub createSubscriptionGroup {
|
|
my $self = shift;
|
|
return undef if ($self->get("subscriptionGroupId"));
|
|
my $group = WebGUI::Group->new($self->session, "new");
|
|
$group->name($self->getId);
|
|
$group->description("The group to store subscriptions for the thread ".$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
|
|
});
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
sub definition {
|
|
my $class = shift;
|
|
my $session = shift;
|
|
my $definition = shift;
|
|
my $i18n = WebGUI::International->new($session,"Asset_Thread");
|
|
push(@{$definition}, {
|
|
assetName=>$i18n->get('assetName'),
|
|
icon=>'thread.gif',
|
|
tableName=>'Thread',
|
|
className=>'WebGUI::Asset::Post::Thread',
|
|
properties=>{
|
|
subscriptionGroupId => {
|
|
noFormPost=>1,
|
|
fieldType=>"hidden",
|
|
defaultValue=>undef
|
|
},
|
|
replies => {
|
|
noFormPost=>1,
|
|
fieldType=>"hidden",
|
|
defaultValue=>undef
|
|
},
|
|
isSticky => {
|
|
fieldType=>"yesNo",
|
|
defaultValue=>0
|
|
},
|
|
isLocked => {
|
|
fieldType=>"yesNo",
|
|
defaultValue=>0
|
|
},
|
|
lastPostId => {
|
|
noFormPost=>1,
|
|
fieldType=>"hidden",
|
|
defaultValue=>undef
|
|
},
|
|
lastPostDate => {
|
|
noFormPost=>1,
|
|
fieldType=>"dateTime",
|
|
defaultValue=>undef
|
|
},
|
|
karma => {
|
|
noFormPost=>1,
|
|
fieldType=>"integer",
|
|
defaultValue=>0
|
|
},
|
|
karmaRank => {
|
|
noFormPost=>1,
|
|
fieldType=>"float",
|
|
defaultValue=>0
|
|
},
|
|
karmaScale => {
|
|
noFormPost=>1,
|
|
fieldType=>"integer",
|
|
defaultValue=>10
|
|
},
|
|
threadRating => {
|
|
noFormPost=>1,
|
|
fieldType=>"hidden",
|
|
defaultValue=>undef
|
|
},
|
|
},
|
|
});
|
|
return $class->SUPER::definition($session,$definition);
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
sub DESTROY {
|
|
my $self = shift;
|
|
return undef unless defined $self;
|
|
$self->{_next}->DESTROY if (defined $self->{_next});
|
|
$self->{_previous}->DESTROY if (defined $self->{_previous});
|
|
$self->SUPER::DESTROY;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getAdjacentThread ( )
|
|
|
|
Given a field and an order, returns the nearest thread when sorting by those.
|
|
|
|
=cut
|
|
|
|
sub getAdjacentThread {
|
|
my $self = shift;
|
|
my $sortBy = shift;
|
|
my $sortOrder = uc shift;
|
|
my $session = $self->session;
|
|
|
|
my $sortCompare = $sortOrder eq 'ASC' ? '>=' : '<=';
|
|
( my $sortByField = $sortBy ) =~ s/.*\.//;
|
|
my $sortCompareValue = $self->get($sortByField);
|
|
|
|
# make sortBy safe to include directly in SQL
|
|
$sortBy = join('.', map { $session->db->dbh->quote_identifier($_) } split(/\./, $sortBy));
|
|
|
|
my $versionTag = WebGUI::VersionTag->getWorking($session, 'nocreate');
|
|
my $tagId = $versionTag ? $versionTag->getId : undef;
|
|
|
|
my ($id, $class, $version) = $self->session->dbSlave->quickArray(<<END_SQL,
|
|
SELECT asset.assetId, asset.className, assetData.revisionDate
|
|
FROM Thread
|
|
INNER JOIN asset ON asset.assetId = Thread.assetId
|
|
INNER JOIN assetData ON assetData.assetId = Thread.assetId AND assetData.revisionDate = Thread.revisionDate
|
|
INNER JOIN Post ON Post.assetId = assetData.assetId AND assetData.revisionDate = Post.revisionDate
|
|
WHERE
|
|
asset.parentId = ?
|
|
AND asset.assetId <> ?
|
|
AND asset.state = 'published'
|
|
AND $sortBy $sortCompare ?
|
|
AND assetData.revisionDate = (
|
|
SELECT MAX(revisionDate)
|
|
FROM assetData
|
|
WHERE
|
|
assetData.assetId = asset.assetId
|
|
AND (
|
|
assetData.status IN ('approved','archived')
|
|
OR assetData.tagId=?
|
|
OR (assetData.ownerUserId=? AND assetData.ownerUserId<>'1')
|
|
)
|
|
)
|
|
ORDER BY $sortBy $sortOrder, assetData.revisionDate $sortOrder
|
|
LIMIT 1
|
|
END_SQL
|
|
[$self->get('parentId'), $self->getId, $sortCompareValue, $tagId, $session->user->userId]
|
|
);
|
|
if ($id) {
|
|
return WebGUI::Asset->new($session, $id, $class, $version);
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getArchiveUrl ( )
|
|
|
|
Formats the url to set the status of a thread archived.
|
|
|
|
=cut
|
|
|
|
sub getArchiveUrl {
|
|
my $self = shift;
|
|
$self->getUrl("func=archive");
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
sub getAutoCommitWorkflowId {
|
|
my $self = shift;
|
|
return $self->getThread->getParent->get("threadApprovalWorkflow");
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
sub getLastPost {
|
|
my $self = shift;
|
|
my $lastPostId = $self->get("lastPostId");
|
|
my $lastPost;
|
|
if ($lastPostId) {
|
|
$lastPost = WebGUI::Asset::Post->new($self->session, $lastPostId);
|
|
}
|
|
return $lastPost if (defined $lastPost);
|
|
return $self;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getLayoutUrl ( layout )
|
|
|
|
Formats the url to change the layout of a thread.
|
|
|
|
=head3 layout
|
|
|
|
A string indicating the type of layout to use. Can be flat or nested.
|
|
|
|
=cut
|
|
|
|
sub getLayoutUrl {
|
|
my $self = shift;
|
|
my $layout = shift;
|
|
return $self->session->asset->getUrl("layout=".$layout.'#id'.$self->session->asset->getId) if ($self->session->asset);
|
|
return $self->getUrl("layout=".$layout);
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getLockUrl ( )
|
|
|
|
Formats the url to lock a thread.
|
|
|
|
=cut
|
|
|
|
sub getLockUrl {
|
|
my $self = shift;
|
|
$self->getUrl("func=lockThread");
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getNextThread ( )
|
|
|
|
Returns a thread object for the next (newer) thread in the same forum.
|
|
|
|
=cut
|
|
|
|
sub getNextThread {
|
|
my $self = shift;
|
|
unless (exists $self->{_next}) {
|
|
my $parent = $self->getParent;
|
|
my $sortBy = $parent->getSortBy;
|
|
my $sortOrder = $parent->getSortOrder;
|
|
$self->{_next} = $self->getAdjacentThread($sortBy, $sortOrder);
|
|
};
|
|
return $self->{_next};
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getPosts ( )
|
|
|
|
Returns a list of the post objects in this thread, including the thread post itself.
|
|
|
|
=cut
|
|
|
|
sub getPosts {
|
|
my $self = shift;
|
|
$self->getLineage(["self","descendants"], {
|
|
returnObjects => 1,
|
|
includeArchived => 1,
|
|
includeOnlyClasses => ["WebGUI::Asset::Post","WebGUI::Asset::Post::Thread"],
|
|
});
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getPreviousThread ( )
|
|
|
|
Returns a thread object for the previous (older) thread in the same forum.
|
|
|
|
=cut
|
|
|
|
sub getPreviousThread {
|
|
my $self = shift;
|
|
unless (exists $self->{_previous}) {
|
|
my $parent = $self->getParent;
|
|
my $sortBy = $parent->getSortBy;
|
|
my $sortOrder = uc $parent->getSortOrder eq 'ASC' ? 'DESC' : 'ASC';
|
|
$self->{_previous} = $self->getAdjacentThread($sortBy, $sortOrder);
|
|
}
|
|
return $self->{_previous};
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getStickUrl ( )
|
|
|
|
Formats the url to make a thread sticky.
|
|
|
|
=cut
|
|
|
|
sub getStickUrl {
|
|
my $self = shift;
|
|
return $self->getUrl("func=stick");
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getSubscribeUrl ( )
|
|
|
|
Formats the url to subscribe to the thread
|
|
|
|
=cut
|
|
|
|
sub getSubscribeUrl {
|
|
my $self = shift;
|
|
return $self->getUrl("func=subscribe");
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
sub getThread {
|
|
return shift;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getUnarchiveUrl ( )
|
|
|
|
Formats the url to set the status of a thread unarchived.
|
|
|
|
=cut
|
|
|
|
sub getUnarchiveUrl {
|
|
my $self = shift;
|
|
$self->getUrl("func=unarchive");
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getUnlockUrl ( )
|
|
|
|
Formats the url to unlock the thread
|
|
|
|
=cut
|
|
|
|
sub getUnlockUrl {
|
|
my $self = shift;
|
|
return $self->getUrl("func=unlockThread");
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getUnstickUrl ( )
|
|
|
|
Formats the url to unstick the thread
|
|
|
|
=cut
|
|
|
|
sub getUnstickUrl {
|
|
my $self = shift;
|
|
return $self->getUrl("func=unstick");
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getUnsubscribeUrl ( )
|
|
|
|
Formats the url to unsubscribe from the thread
|
|
|
|
=cut
|
|
|
|
sub getUnsubscribeUrl {
|
|
my $self = shift;
|
|
return $self->getUrl("func=unsubscribe");
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 isThreadLocked ( )
|
|
|
|
Returns a boolean indicating whether this thread is locked from new posts and other edits.
|
|
|
|
=cut
|
|
|
|
sub isThreadLocked {
|
|
my ($self) = @_;
|
|
return $self->get("isLocked");
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 incrementReplies ( lastPostDate, lastPostId )
|
|
|
|
Increments the replies counter for this thread.
|
|
|
|
=head3 lastPostDate
|
|
|
|
The date of the reply that caused the replies counter to be incremented.
|
|
|
|
=head3 lastPostId
|
|
|
|
The id of the reply that caused the replies counter to be incremented.
|
|
|
|
=cut
|
|
|
|
sub incrementReplies {
|
|
my ($self, $dateOfReply, $replyId) = @_;
|
|
$self->update({replies=>$self->getDescendantCount, lastPostId=>$replyId, lastPostDate=>$dateOfReply});
|
|
$self->getParent->incrementReplies($dateOfReply,$replyId);
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 incrementViews ( )
|
|
|
|
Increments the views counter for this thread.
|
|
|
|
=cut
|
|
|
|
sub incrementViews {
|
|
my ($self) = @_;
|
|
$self->update({views=>$self->get("views")+1});
|
|
$self->getParent->incrementViews;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 isMarkedRead ( )
|
|
|
|
Returns a boolean indicating whether this thread is marked read for the user.
|
|
|
|
=cut
|
|
|
|
sub isMarkedRead {
|
|
my $self = shift;
|
|
return 1 if $self->isPoster;
|
|
my ($isRead) = $self->session->db->quickArray("select count(*) from Thread_read where threadId=? and userId=?",[$self->getId,$self->session->user->userId]);
|
|
return $isRead;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 isSticky ( )
|
|
|
|
Returns a boolean indicating whether this thread should be "stuck" a the top of the forum and not be sorted with the rest of the threads.
|
|
|
|
=cut
|
|
|
|
sub isSticky {
|
|
my ($self) = @_;
|
|
return $self->get("isSticky");
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 isSubscribed ( )
|
|
|
|
Returns a boolean indicating whether the user is subscribed to this thread.
|
|
|
|
=cut
|
|
|
|
sub isSubscribed {
|
|
my $self = shift;
|
|
return $self->session->user->isInGroup($self->get("subscriptionGroupId"));
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 lock ( )
|
|
|
|
Sets this thread to be locked from edits.
|
|
|
|
=cut
|
|
|
|
sub lock {
|
|
my ($self) = @_;
|
|
$self->update({isLocked=>1});
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 markRead ( )
|
|
|
|
Marks this post read for this user.
|
|
|
|
=cut
|
|
|
|
sub markRead {
|
|
my $self = shift;
|
|
$self->session->db->write("replace into Thread_read (threadId, userId) values (?,?)",[$self->getId,$self->session->user->userId]);
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 prepareView ( )
|
|
|
|
See WebGUI::Asset::prepareView() for details.
|
|
|
|
=cut
|
|
|
|
sub prepareView {
|
|
my $self = shift;
|
|
$self->SUPER::prepareView();
|
|
my $template = WebGUI::Asset::Template->new($self->session, $self->getParent->get("threadTemplateId"));
|
|
$template->prepare($self->getMetaDataAsTemplateVariables);
|
|
$self->{_viewTemplate} = $template;
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
sub postProcess {
|
|
my $self = shift;
|
|
if ($self->getParent->canEdit) {
|
|
my $karmaScale = $self->session->form->process("karmaScale","integer") || $self->getParent->get("defaultKarmaScale");
|
|
my $karmaRank = $self->get("karma")/$karmaScale;
|
|
$self->update({karmaScale=>$karmaScale, karmaRank=>$karmaRank});
|
|
}
|
|
$self->SUPER::postProcess;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
sub processPropertiesFromFormPost {
|
|
my $self = shift;
|
|
|
|
if ($self->isNew && $self->getParent->getValue('useCaptcha')) {
|
|
my $captchaOk = $self->session->form->process("captcha","Captcha");
|
|
|
|
return [ 'invalid captcha' ] unless $captchaOk;
|
|
}
|
|
|
|
return $self->SUPER::processPropertiesFromFormPost;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
sub purge {
|
|
my $self = shift;
|
|
$self->session->db->write("delete from Thread_read where threadId=?",[$self->getId]);
|
|
$self->SUPER::purge;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 rate ( rating )
|
|
|
|
Stores a rating against this post.
|
|
|
|
=head3 rating
|
|
|
|
An integer between 1 and 5 (5 being best) to rate this post with.
|
|
|
|
=cut
|
|
|
|
sub rate {
|
|
my $self = shift;
|
|
my $rating = shift;
|
|
return undef unless ($rating == -1 || $rating == 1);
|
|
return undef if $self->hasRated;
|
|
$self->SUPER::rate($rating);
|
|
|
|
##Thread specific karma adjustment for CS
|
|
if ($self->session->setting->get("useKarma")) {
|
|
my $poster = WebGUI::User->new($self->session, $self->get("ownerUserId"));
|
|
$poster->karma($rating*$self->getParent->get("karmaRatingMultiplier"),"collaboration rating","someone rated post ".$self->getId);
|
|
my $rater = WebGUI::User->new($self->session->user->userId);
|
|
$rater->karma(-$self->getParent->get("karmaSpentToRate"),"collaboration rating","spent karma to rate post ".$self->getId);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 setLastPost ( id, date )
|
|
|
|
Sets the last reply of this thread.
|
|
|
|
=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});
|
|
$self->getParent->setLastPost($id,$date);
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
sub normalizeLastPost {
|
|
my $self = shift;
|
|
# Hmm. Is this right?
|
|
my ($lastPostId, $lastPostDate) = $self->session->db->quickArray("SELECT a.assetId, a.creationDate FROM asset as a INNER JOIN Post as t ON a.assetId = t.assetId WHERE t.threadId = ? ORDER BY a.creationDate DESC LIMIT 1", [$self->getId]);
|
|
$self->setLastPost($lastPostId, $lastPostDate);
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 setParent ( newParent )
|
|
|
|
We're overloading the setParent in Asset because we don't want threads to be able to be posted to anything other than other collaboration systems.
|
|
|
|
=head3 newParent
|
|
|
|
An asset object to make the parent of this asset.
|
|
|
|
=cut
|
|
|
|
sub setParent {
|
|
my $self = shift;
|
|
my $newParent = shift;
|
|
return 0 unless ($newParent->isa("WebGUI::Asset::Wobject::Collaboration"));
|
|
# specify the Asset package here directly because we don't want to use the ruls in WebGUI::Asset::Post, as they don't fit for Threads.
|
|
return $self->WebGUI::Asset::setParent($newParent);
|
|
}
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 stick ( )
|
|
|
|
Makes this thread sticky.
|
|
|
|
=cut
|
|
|
|
sub stick {
|
|
my ($self) = @_;
|
|
$self->update({isSticky=>1});
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 subscribe ( )
|
|
|
|
Subscribes the user to this thread.
|
|
|
|
=cut
|
|
|
|
sub subscribe {
|
|
my $self = shift;
|
|
$self->createSubscriptionGroup;
|
|
my $group = WebGUI::Group->new($self->session,$self->get("subscriptionGroupId"));
|
|
$group->addUsers([$self->session->user->userId]);
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 sumReplies ( )
|
|
|
|
Calculates the number of replies to this thread and updates the counter to reflect that. Also triggers a count in the collaboration system.
|
|
|
|
=cut
|
|
|
|
sub sumReplies {
|
|
my $self = shift;
|
|
$self->update({replies=>$self->getDescendantCount});
|
|
$self->getParent->sumReplies;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 trash
|
|
|
|
Moves thread to the trash and updates reply counter on thread.
|
|
|
|
=cut
|
|
|
|
sub trash {
|
|
my $self = shift;
|
|
$self->SUPER::trash;
|
|
$self->getParent->sumReplies;
|
|
if ($self->getParent->get("lastPostId") eq $self->getId) {
|
|
my $parentLineage = $self->getThread->get("lineage");
|
|
my ($id, $date) = $self->session->db->quickArray("select assetId, creationDate from asset where
|
|
lineage like ? and assetId<>? and asset.state='published' and className like 'WebGUI::Asset::Post%'
|
|
order by creationDate desc",[$parentLineage.'%', $self->getId]);
|
|
if (defined $id) {
|
|
$self->getParent->setLastPost($id,$date);
|
|
}
|
|
else {
|
|
$self->getParent->setLastPost('','');
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 unarchive ( )
|
|
|
|
Unarchives this thread.
|
|
|
|
=cut
|
|
|
|
sub unarchive {
|
|
my $self = shift;
|
|
foreach my $post (@{$self->getPosts}) {
|
|
$post->setStatusUnarchived;
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 unlock ( )
|
|
|
|
Negates the lock method.
|
|
|
|
=cut
|
|
|
|
sub unlock {
|
|
my ($self) = @_;
|
|
$self->update({isLocked=>0});
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 unmarkRead ( )
|
|
|
|
unmarks this post read for all users.
|
|
|
|
=cut
|
|
|
|
sub unmarkRead {
|
|
my $self = shift;
|
|
$self->session->db->write("delete from Thread_read where threadId=?",[$self->getId]);
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 unstick ( )
|
|
|
|
Negates the stick method.
|
|
|
|
=cut
|
|
|
|
sub unstick {
|
|
my ($self) = @_;
|
|
$self->update({isSticky=>0});
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 unsubscribe ( )
|
|
|
|
Negates the subscribe method.
|
|
|
|
=cut
|
|
|
|
sub unsubscribe {
|
|
my $self = shift;
|
|
my $group = WebGUI::Group->new($self->session,$self->get("subscriptionGroupId"));
|
|
return
|
|
if !$group;
|
|
$group->deleteUsers([$self->session->user->userId]);
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 updateThreadRating ( )
|
|
|
|
Update the cumulative ratings in this thread
|
|
|
|
=cut
|
|
|
|
sub updateThreadRating {
|
|
my $self = shift;
|
|
my $session = $self->session;
|
|
|
|
my $calcRating = 0;
|
|
my $postIds = $self->getLineage(["descendants","self"], {
|
|
includeOnlyClasses => ["WebGUI::Asset::Post","WebGUI::Asset::Post::Thread"],
|
|
includeArchived => 1,
|
|
});
|
|
|
|
$calcRating += $session->db->quickScalar(
|
|
"SELECT SUM(rating) FROM Post_rating WHERE assetId IN (".$session->db->quoteAndJoin($postIds).")"
|
|
);
|
|
|
|
$self->update({
|
|
threadRating => $calcRating
|
|
});
|
|
|
|
my $parent = $self->getParent;
|
|
if (defined $parent) {
|
|
$parent->recalculateRating;
|
|
} else {
|
|
$self->session->errorHandler->error("Couldn't get parent for thread ".$self->getId);
|
|
}
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 validParent
|
|
|
|
Make sure that the current session asset is a CS for pasting and adding checks.
|
|
|
|
This is a class method.
|
|
|
|
=cut
|
|
|
|
sub validParent {
|
|
my $class = shift;
|
|
my $session = shift;
|
|
return $session->asset->isa('WebGUI::Asset::Wobject::Collaboration');
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
sub view {
|
|
my $self = shift;
|
|
my $currentPost = shift || $self;
|
|
$self->markRead;
|
|
$self->incrementViews unless ($self->session->form->process("func") eq 'rate');
|
|
if ($self->session->user->isVisitor && !$self->session->form->process("layout")) {
|
|
my $out = WebGUI::Cache->new($self->session,"view_".$self->getId)->get;
|
|
return $out if $out;
|
|
}
|
|
$self->session->scratch->set("discussionLayout",$self->session->form->process("layout")) if ($self->session->form->process("layout"));
|
|
my $layout = $self->session->scratch->get("discussionLayout") || $self->session->user->profileField("discussionLayout");
|
|
my $var = $self->getTemplateVars;
|
|
$self->getParent->appendTemplateLabels($var);
|
|
|
|
$var->{'karmaIsEnabled' } = $self->session->setting->get("useKarma");
|
|
$var->{'user.isVisitor' } = ($self->session->user->isVisitor);
|
|
$var->{'user.isModerator' } = $self->getParent->canModerate;
|
|
$var->{'user.canPost' } = $self->getParent->canPost;
|
|
$var->{'user.canReply' } = $self->canReply;
|
|
$var->{'repliesAllowed' } = $self->getParent->get("allowReplies");
|
|
|
|
$var->{'layout.nested.url' } = $self->getLayoutUrl("nested");
|
|
$var->{'layout.flat.url' } = $self->getLayoutUrl("flat");
|
|
$var->{'layout.isFlat' } = ($layout eq "flat");
|
|
$var->{'layout.isNested' } = ($layout eq "nested" || !$var->{'layout.isFlat'});
|
|
|
|
$var->{'user.isSubscribed' } = $self->isSubscribed;
|
|
$var->{'subscribe.url' } = $self->getSubscribeUrl;
|
|
$var->{'unsubscribe.url' } = $self->getUnsubscribeUrl;
|
|
|
|
$var->{'thumbsUp.icon.url' } = $self->session->url->extras('thumbup.gif');
|
|
$var->{'thumbsDown.icon.url'} = $self->session->url->extras('thumbdown.gif');
|
|
|
|
$var->{'isArchived' } = $self->get("status") eq "archived";
|
|
$var->{'archive.url' } = $self->getArchiveUrl;
|
|
$var->{'unarchive.url' } = $self->getUnarchiveUrl;
|
|
|
|
$var->{'isSticky' } = $self->isSticky;
|
|
$var->{'stick.url' } = $self->getStickUrl;
|
|
$var->{'unstick.url' } = $self->getUnstickUrl;
|
|
|
|
$var->{'isLocked' } = $self->isThreadLocked;
|
|
$var->{'lock.url' } = $self->getLockUrl;
|
|
$var->{'unlock.url' } = $self->getUnlockUrl;
|
|
|
|
$var->{'transfer.karma.form'} = WebGUI::Form::formHeader($self->session, {
|
|
action=>$self->getUrl
|
|
});
|
|
|
|
$var->{'transfer.karma.form'} .= WebGUI::Form::hidden($self->session, {
|
|
name=>"func",
|
|
value=>"transferKarma"
|
|
});
|
|
$var->{'transfer.karma.form'} .= WebGUI::Form::integer($self->session, {
|
|
name=>"karma",
|
|
value=>10
|
|
});
|
|
$var->{'transfer.karma.form'} .= WebGUI::Form::submit($self->session);
|
|
$var->{'transfer.karma.form'} .= WebGUI::Form::formFooter($self->session);
|
|
|
|
my $p = WebGUI::Paginator->new($self->session,$self->getUrl,$self->getParent->get("postsPerPage"));
|
|
my $sql = "select asset.assetId, asset.className, assetData.revisionDate as revisionDate, assetData.url as url from asset
|
|
left join assetData on assetData.assetId=asset.assetId
|
|
where asset.lineage like ".$self->session->db->quote($self->get("lineage").'%')
|
|
." and asset.state='published'
|
|
and asset.className like 'WebGUI::Asset::Post%'
|
|
and assetData.revisionDate=(SELECT max(assetData.revisionDate) from assetData where assetData.assetId=asset.assetId
|
|
and (
|
|
assetData.status in ('approved','archived')
|
|
or assetData.tagId=".$self->session->db->quote($self->session->scratch->get("versionTag"));
|
|
$sql .= " or assetData.status='pending'" if ($self->getParent->canEdit);
|
|
$sql .= " or (assetData.ownerUserId=".$self->session->db->quote($self->session->user->userId)." and assetData.ownerUserId<>'1')
|
|
))
|
|
group by assetData.assetId
|
|
order by ";
|
|
|
|
if ($layout eq "flat") {
|
|
$sql .= "asset.creationDate";
|
|
} else {
|
|
$sql .= "asset.lineage";
|
|
}
|
|
|
|
my $currentPageUrl = $self->session->url->getRequestedUrl;
|
|
$p->setDataByQuery($sql, undef, undef, undef, "url", $currentPageUrl);
|
|
foreach my $dataSet (@{$p->getPageData()}) {
|
|
next unless ($dataSet->{className} eq "WebGUI::Asset::Post" || $dataSet->{className} eq "WebGUI::Asset::Post::Thread"); #handle non posts!
|
|
my $reply = WebGUI::Asset::Post->new($self->session, $dataSet->{assetId}, $dataSet->{className}, $dataSet->{revisionDate});
|
|
$reply->{'_thread' } = $self; # caching thread for better performance
|
|
my %replyVars = %{$reply->getTemplateVars};
|
|
$replyVars{isCurrent } = ($reply->getId eq $currentPost->getId);
|
|
$replyVars{isThreadRoot } = $self->getId eq $reply->getId;
|
|
$replyVars{depth } = $reply->getLineageLength - $self->getLineageLength;
|
|
$replyVars{depthX10 } = $replyVars{depth}*10;
|
|
my @depth_loop;
|
|
for (my $i=0; $i<$replyVars{depth}; $i++) {
|
|
push(@{$replyVars{indent_loop}},{depth=>$i});
|
|
}
|
|
push (@{$var->{post_loop}}, \%replyVars);
|
|
}
|
|
$p->appendTemplateVars($var);
|
|
$var->{'add.url'} = $self->getParent->getNewThreadUrl;
|
|
my $prev = $self->getPreviousThread;
|
|
$var->{"previous.url" } = $prev->getUrl if $prev;
|
|
my $next = $self->getNextThread;
|
|
$var->{"next.url" } = $next->getUrl if $next;
|
|
|
|
$var->{"search.url" } = $self->getParent->getSearchUrl;
|
|
$var->{"collaboration.url" } = $self->getThread->getParent->getUrl;
|
|
$var->{'collaboration.title' } = $self->getParent->get("title");
|
|
$var->{'collaboration.description'} = $self->getParent->get("description");
|
|
my $out = $self->processTemplate($var,undef,$self->{_viewTemplate});
|
|
|
|
if ($self->session->user->isVisitor && !$self->session->form->process("layout")) {
|
|
WebGUI::Cache->new($self->session,"view_".$self->getId)->set($out,$self->getThread->getParent->get("visitorCacheTimeout"));
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_archive ( )
|
|
|
|
The web method to archive all the posts in this thread.
|
|
|
|
=cut
|
|
|
|
sub www_archive {
|
|
my $self = shift;
|
|
$self->archive if ($self->canEdit);
|
|
return $self->www_view;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_lock ( )
|
|
|
|
The web method to lock a thread.
|
|
|
|
=cut
|
|
|
|
sub www_lockThread {
|
|
my $self = shift;
|
|
$self->lock if $self->getParent->canEdit;
|
|
return $self->www_view;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_nextThread ( )
|
|
|
|
Displays the next logical thread after this one.
|
|
|
|
NOTE:
|
|
|
|
This method is deprecated. It messes with macros via $session->asset.
|
|
|
|
=cut
|
|
|
|
sub www_nextThread {
|
|
my $self = shift;
|
|
my $next = $self->getNextThread;
|
|
if (defined $next) {
|
|
return $next->www_view;
|
|
}
|
|
return $self->getParent->www_view;
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_previousThread ( )
|
|
|
|
Displays the previous logical thread before this one.
|
|
|
|
NOTE:
|
|
|
|
This method is deprecated. It messes with macros via $session->asset.
|
|
|
|
=cut
|
|
|
|
sub www_previousThread {
|
|
my $self = shift;
|
|
my $previous = $self->getPreviousThread;
|
|
if (defined $previous) {
|
|
return $previous->www_view;
|
|
}
|
|
return $self->getParent->www_view;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_stick ( )
|
|
|
|
The web method to make a thread sticky.
|
|
|
|
=cut
|
|
|
|
sub www_stick {
|
|
my $self = shift;
|
|
$self->stick if $self->getParent->canEdit;
|
|
return $self->www_view;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_subscribe ( )
|
|
|
|
The web method to subscribe to a thread.
|
|
|
|
=cut
|
|
|
|
sub www_subscribe {
|
|
my $self = shift;
|
|
$self->subscribe if $self->canSubscribe;
|
|
return $self->www_view;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_transferKarma ( )
|
|
|
|
Transfers karma from the current user to this thread.
|
|
|
|
=cut
|
|
|
|
sub www_transferKarma {
|
|
my $self = shift;
|
|
my $amount = $self->session->form->get("karma","integer");
|
|
# cant have them giving more karma then they have
|
|
if ($amount > 0 && $amount <= $self->session->user->karma) {
|
|
$self->session->user->karma(-$amount, "Thread ".$self->getId, "Transferring karma to a thread.");
|
|
my $newKarma = $self->get("karma")+$amount;
|
|
my $karmaScale = $self->get("karmaScale") || 1;
|
|
$self->update({karma=>$newKarma,karmaRank=>$newKarma/$karmaScale});
|
|
}
|
|
return $self->www_view;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_unarchive ( )
|
|
|
|
The web method to unarchive all the posts in this thread.
|
|
|
|
=cut
|
|
|
|
sub www_unarchive {
|
|
my $self = shift;
|
|
$self->unarchive if ($self->canEdit);
|
|
return $self->www_view;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_unlock ( )
|
|
|
|
The web method to unlock a thread.
|
|
|
|
=cut
|
|
|
|
sub www_unlockThread {
|
|
my $self = shift;
|
|
$self->unlock if $self->getParent->canEdit;
|
|
return $self->www_view;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_unstick ( )
|
|
|
|
The web method to make a sticky thread normal again.
|
|
|
|
=cut
|
|
|
|
sub www_unstick {
|
|
my $self = shift;
|
|
$self->unstick if $self->getParent->canEdit;
|
|
$self->www_view;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_threadUnsubscribe ( )
|
|
|
|
The web method to unsubscribe from a thread.
|
|
|
|
=cut
|
|
|
|
sub www_unsubscribe {
|
|
my $self = shift;
|
|
$self->unsubscribe if $self->canSubscribe;
|
|
return $self->www_view;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_view ( )
|
|
|
|
Renders self->view based upon current style, subject to timeouts. Returns Privilege::noAccess() if canView is False.
|
|
|
|
=cut
|
|
|
|
sub www_view {
|
|
my $self = shift;
|
|
my $currentPost = shift;
|
|
return $self->session->privilege->noAccess() unless $self->canView;
|
|
my $check = $self->checkView;
|
|
return $check if (defined $check);
|
|
$self->session->http->setCacheControl($self->get("visitorCacheTimeout")) if ($self->session->user->isVisitor);
|
|
$self->session->http->sendHeader;
|
|
$self->prepareView;
|
|
my $style = $self->getParent->processStyle($self->getSeparator);
|
|
my ($head, $foot) = split($self->getSeparator,$style);
|
|
$self->session->output->print($head,1);
|
|
$self->session->output->print($self->view($currentPost));
|
|
$self->session->output->print($foot,1);
|
|
return "chunked";
|
|
}
|
|
|
|
|
|
|
|
1;
|
|
|