FIX: restore spam, rss, delete, approve and ham controller actions on the front end.

This commit is contained in:
Will Rossiter 2012-07-22 13:30:33 +12:00
parent 41f3c61718
commit 95667fdf41
5 changed files with 303 additions and 88 deletions

View File

@ -66,7 +66,16 @@ class Commenting {
Object::remove_extension($class, 'CommentsExtension'); Object::remove_extension($class, 'CommentsExtension');
} }
/**
* Returns whether a given class name has commenting enabled
*
* @return bool
*/
public static function has_commenting($class) {
return (isset(self::$enabled_classes[$class]));
}
/** /**
* Sets a value for a class of a given config setting. Passing 'all' as the class * Sets a value for a class of a given config setting. Passing 'all' as the class
* sets it for everything * sets it for everything

View File

@ -6,8 +6,12 @@
class CommentingController extends Controller { class CommentingController extends Controller {
static $allowed_actions = array( public static $allowed_actions = array(
'delete', 'delete',
'spam',
'ham',
'approve',
'rss',
'CommentsForm', 'CommentsForm',
'doPostComment' 'doPostComment'
); );
@ -42,38 +46,194 @@ class CommentingController extends Controller {
/** /**
* Workaround for generating the link to this controller * Workaround for generating the link to this controller
*
* @return string
*/ */
public function Link($action = "") { public function Link($action = "", $id = '', $other = '') {
return __CLASS__ .'/'. $action; return Controller::join_links(__CLASS__ , $action, $id, $other);
} }
/** /**
* Performs the delete task for deleting {@link Comment}. * Return an RSS feed of comments for a given set of comments or all
* comments on the website.
* *
* /delete/$ID deletes the $ID comment * To maintain backwards compatibility with 2.4 this supports mapping
* of PageComment/rss?pageid= as well as the new RSS format for comments
* of CommentingController/rss/{classname}/{id}
*
* @return RSS
*/ */
public function delete() { public function rss() {
$link = $this->Link('rss');
$class = $this->urlParams['ID'];
$id = $this->urlParams['OtherID'];
if(isset($_GET['pageid'])) {
$id = Convert::raw2sql($_GET['pageid']);
$comments = Comment::get()->where(sprintf(
"BaseClass = 'SiteTree' AND ParentID = '%s'", $id
));
$link = $this->Link('rss', 'SiteTree', $id);
} else if($class && $id) {
if(Commenting::has_commenting($class)) {
$comments = Comment::get()->where(sprintf(
"BaseClass = '%s' AND ParentID = '%s'",
Convert::raw2sql($class),
Convert::raw2sql($id)
));
$link = $this->Link('rss', Convert::raw2xml($class), (int) $id);
} else {
return $this->httpError(404);
}
} else if($class) {
if(Commenting::has_commenting($class)) {
$comments = Comment::get()->where(sprintf(
"BaseClass = '%s'", Convert::raw2sql($class)
));
} else {
return $this->httpError(404);
}
} else {
$comments = Comment::get();
}
$title = _t('CommentingController.RSSTITLE', "Comments RSS Feed");
$feed = new RSSFeed($comments, $link, $title, $link, 'Title', 'Comment', 'AuthorName');
$feed->outputToBrowser();
}
/**
* Deletes a given {@link Comment} via the URL.
*
* @param SS_HTTPRequest
*/
public function delete($request) {
if(!$this->checkSecurityToken($request)) {
return $this->httpError(400);
}
if(($comment = $this->getComment()) && $comment->canDelete()) {
$comment->delete();
return ($this->request->isAjax()) ? true : $this->redirectBack();
}
return $this->httpError(404);
}
/**
* Marks a given {@link Comment} as spam. Removes the comment from display
*
* @param SS_HTTPRequest
*/
public function spam() {
if(!$this->checkSecurityToken($request)) {
return $this->httpError(400);
}
$comment = $this->getComment();
if(($comment = $this->getComment()) && $comment->canEdit()) {
$comment->IsSpam = true;
$comment->Moderated = true;
$comment->write();
return ($this->request->isAjax()) ? true : $this->redirectBack();
}
return $this->httpError(404);
}
/**
* Marks a given {@link Comment} as ham (not spam).
*
* @param SS_HTTPRequest
*/
public function ham($request) {
if(!$this->checkSecurityToken($request)) {
return $this->httpError(400);
}
$comment = $this->getComment();
if(($comment = $this->getComment()) && $comment->canEdit()) {
$comment->IsSpam = false;
$comment->Moderated = true;
$comment->write();
return ($this->request->isAjax()) ? true : $this->redirectBack();
}
return $this->httpError(404);
}
/**
* Marks a given {@link Comment} as approved.
*
* @param SS_HTTPRequest
*/
public function approve($request) {
if(!$this->checkSecurityToken($request)) {
return $this->httpError(400);
}
$comment = $this->getComment();
if(($comment = $this->getComment()) && $comment->canEdit()) {
$comment->IsSpam = false;
$comment->Moderated = true;
$comment->write();
return ($this->request->isAjax()) ? true : $this->redirectBack();
}
return $this->httpError(404);
}
/**
* Returns the comment referenced in the URL (by ID).
*
* @return Comment|false
*/
public function getComment() {
$id = isset($this->urlParams['ID']) ? $this->urlParams['ID'] : false; $id = isset($this->urlParams['ID']) ? $this->urlParams['ID'] : false;
if($id) { if($id) {
$comment = DataObject::get_by_id('Comment', $id); $comment = DataObject::get_by_id('Comment', $id);
if($comment && $comment->canDelete()) { if($comment) {
$comment->delete(); return $comment;
return ($this->request->isAjax()) ? true : $this->redirectBack();
} }
} }
return ($this->request->isAjax()) ? false : $this->httpError('404'); return false;
} }
/**
* Checks the security token given with the URL to prevent CSRF attacks
* against administrators allowing users to hijack comment moderation.
*
* @param SS_HTTPRequest
*
* @return boolean
*/
public function checkSecurityToken($req) {
$token = SecurityToken::inst();
return $token->checkRequest($req);
}
/** /**
* Post a comment form * Post a comment form
* *
* @return Form * @return Form
*/ */
function CommentsForm() { public function CommentsForm() {
$member = Member::currentUser(); $member = Member::currentUser();
$fields = new FieldList( $fields = new FieldList(
@ -143,6 +303,10 @@ class CommentingController extends Controller {
"Comment" => Cookie::get('CommentsForm_Comment') "Comment" => Cookie::get('CommentsForm_Comment')
)); ));
} }
if($member) {
$form->loadDataFrom($member);
}
// hook to allow further extensions to alter the comments form // hook to allow further extensions to alter the comments form
$this->extend('alterCommentForm', $form); $this->extend('alterCommentForm', $form);
@ -156,7 +320,7 @@ class CommentingController extends Controller {
* @param array $data * @param array $data
* @param Form $form * @param Form $form
*/ */
function doPostComment($data, $form) { public function doPostComment($data, $form) {
$class = (isset($data['BaseClass'])) ? $data['BaseClass'] : $this->getBaseClass(); $class = (isset($data['BaseClass'])) ? $data['BaseClass'] : $this->getBaseClass();
// if no class then we cannot work out what controller or model they // if no class then we cannot work out what controller or model they

View File

@ -7,7 +7,7 @@
*/ */
class Comment extends DataObject { class Comment extends DataObject {
static $db = array( public static $db = array(
"Name" => "Varchar(200)", "Name" => "Varchar(200)",
"Comment" => "Text", "Comment" => "Text",
"Email" => "Varchar(200)", "Email" => "Varchar(200)",
@ -15,27 +15,29 @@ class Comment extends DataObject {
"BaseClass" => "Varchar(200)", "BaseClass" => "Varchar(200)",
"Moderated" => "Boolean", "Moderated" => "Boolean",
"IsSpam" => "Boolean", "IsSpam" => "Boolean",
'NeedsModeration' => 'Boolean', "ParentID" => "Int"
); );
static $has_one = array( public static $has_one = array(
"Parent" => "DataObject",
"Author" => "Member" "Author" => "Member"
); );
static $has_many = array(); public static $default_sort = "Created DESC";
static $many_many = array(); public static $has_many = array();
static $defaults = array( public static $many_many = array();
public static $defaults = array(
"Moderated" => true "Moderated" => true
); );
static $casting = array( public static $casting = array(
"RSSTitle" => "Varchar", 'AuthorName' => 'Varchar',
'RSSName' => 'Varchar'
); );
static $searchable_fields = array( public static $searchable_fields = array(
'Name', 'Name',
'Email', 'Email',
'Comment', 'Comment',
@ -43,12 +45,13 @@ class Comment extends DataObject {
'BaseClass', 'BaseClass',
); );
static $summary_fields = array( public static $summary_fields = array(
'Name' => 'Submitted By', 'Name' => 'Submitted By',
'Email' => 'Email', 'Email' => 'Email',
'Comment' => 'Comment', 'Comment' => 'Comment',
'Created' => 'Date Posted', 'Created' => 'Date Posted',
'ParentTitle' => 'Parent', 'ParentTitle' => 'Parent',
'IsSpam' => 'Is Spam'
); );
@ -87,7 +90,7 @@ class Comment extends DataObject {
* @return string link to this comment. * @return string link to this comment.
*/ */
public function Link($action = "") { public function Link($action = "") {
return $this->Parent()->Link($action) . '#' . $this->Permalink(); return $this->getParent()->Link($action) . '#' . $this->Permalink();
} }
/** /**
@ -103,9 +106,11 @@ class Comment extends DataObject {
} }
/** /**
* @param boolean $includerelations a boolean value to indicate if the labels returned include relation fields * Translate the form field labels for the CMS administration
*
* @param boolean $includerelations
*/ */
function fieldLabels($includerelations = true) { public function fieldLabels($includerelations = true) {
$labels = parent::fieldLabels($includerelations); $labels = parent::fieldLabels($includerelations);
$labels['Name'] = _t('Comment.NAME', 'Author Name'); $labels['Name'] = _t('Comment.NAME', 'Author Name');
$labels['Comment'] = _t('Comment.COMMENT', 'Comment'); $labels['Comment'] = _t('Comment.COMMENT', 'Comment');
@ -132,8 +137,9 @@ class Comment extends DataObject {
* *
* @return string * @return string
*/ */
function getParentTitle(){ public function getParentTitle(){
$parent = $this->getParent(); $parent = $this->getParent();
return ($parent->Title) ? $parent->Title : $parent->ClassName . " #" . $parent->ID; return ($parent->Title) ? $parent->Title : $parent->ClassName . " #" . $parent->ID;
} }
@ -142,20 +148,18 @@ class Comment extends DataObject {
* *
* @return Boolean * @return Boolean
*/ */
function canCreate($member = null) { public function canCreate($member = null) {
return false; return false;
} }
/** /**
* Checks for association with a page, * Checks for association with a page, and {@link SiteTree->ProvidePermission}
* and {@link SiteTree->ProvidePermission} flag being set to TRUE. * flag being set to true.
* Note: There's an additional layer of permission control
* in {@link PageCommentInterface}.
* *
* @param Member $member * @param Member $member
* @return Boolean * @return Boolean
*/ */
function canView($member = null) { public function canView($member = null) {
if(!$member) $member = Member::currentUser(); if(!$member) $member = Member::currentUser();
// Standard mechanism for accepting permission changes from decorators // Standard mechanism for accepting permission changes from decorators
@ -170,13 +174,13 @@ class Comment extends DataObject {
} }
/** /**
* Checks for "CMS_ACCESS_CommentAdmin" permission codes * Checks for "CMS_ACCESS_CommentAdmin" permission codes and
* and {@link canView()}. * {@link canView()}.
* *
* @param Member $member * @param Member $member
* @return Boolean * @return Boolean
*/ */
function canEdit($member = null) { public function canEdit($member = null) {
if(!$member) $member = Member::currentUser(); if(!$member) $member = Member::currentUser();
// Standard mechanism for accepting permission changes from decorators // Standard mechanism for accepting permission changes from decorators
@ -189,13 +193,13 @@ class Comment extends DataObject {
} }
/** /**
* Checks for "CMS_ACCESS_CommentAdmin" permission codes * Checks for "CMS_ACCESS_CommentAdmin" permission codes and
* and {@link canEdit()}. * {@link canEdit()}.
* *
* @param Member $member * @param Member $member
* @return Boolean * @return Boolean
*/ */
function canDelete($member = null) { public function canDelete($member = null) {
if(!$member) $member = Member::currentUser(); if(!$member) $member = Member::currentUser();
// Standard mechanism for accepting permission changes from decorators // Standard mechanism for accepting permission changes from decorators
@ -204,40 +208,76 @@ class Comment extends DataObject {
return $this->canEdit($member); return $this->canEdit($member);
} }
/**
/************************************ Review the following */ * Return the authors name for the comment
function getRSSName() { *
* @return string
*/
public function getAuthorName() {
if($this->Name) { if($this->Name) {
return $this->Name; return $this->Name;
} elseif($this->Author()) { } else if($this->Author()) {
return $this->Author()->getName(); return $this->Author()->getName();
} }
} }
function DeleteLink() { /**
return ($this->canDelete()) ? "PageComment_Controller/deletecomment/$this->ID" : false; * @return string
*/
public function DeleteLink() {
if($this->canDelete()) {
$token = SecurityToken::inst();
return DBField::create_field("Varchar", $token->addToUrl(sprintf(
"CommentingController/delete/%s", (int) $this->ID
)));
}
} }
function CommentTextWithLinks() { /**
$pattern = '|([a-zA-Z]+://)([a-zA-Z0-9?&%.;:/=+_-]*)|is'; * @return string
$replace = '<a rel="nofollow" href="$1$2">$1$2</a>'; */
return preg_replace($pattern, $replace, $this->Comment); public function SpamLink() {
if($this->canEdit() && !$this->IsSpam) {
$token = SecurityToken::inst();
return DBField::create_field("Varchar", $token->addToUrl(sprintf(
"CommentingController/spam/%s", (int) $this->ID
)));
}
} }
function SpamLink() { /**
return ($this->canEdit() && !$this->IsSpam) ? "PageComment_Controller/reportspam/$this->ID" : false; * @return string
*/
public function HamLink() {
if($this->canEdit() && $this->IsSpam) {
$token = SecurityToken::inst();
return DBField::create_field("Varchar", $token->addToUrl(sprintf(
"CommentingController/ham/%s", (int) $this->ID
)));
}
} }
function HamLink() { /**
return ($this->canEdit() && $this->IsSpam) ? "PageComment_Controller/reportham/$this->ID" : false; * @return string
*/
public function ApproveLink() {
if($this->canEdit() && !$this->Moderated) {
$token = SecurityToken::inst();
return DBField::create_field("Varchar", $token->addToUrl(sprintf(
"CommentingController/approve/%s", (int) $this->ID
)));
}
} }
function ApproveLink() { /**
return ($this->canEdit() && $this->NeedsModeration) ? "PageComment_Controller/approve/$this->ID" : false; * @return string
} */
public function SpamClass() {
function SpamClass() {
if($this->getField('IsSpam')) { if($this->getField('IsSpam')) {
return 'spam'; return 'spam';
} else if($this->getField('NeedsModeration')) { } else if($this->getField('NeedsModeration')) {
@ -247,12 +287,18 @@ class Comment extends DataObject {
} }
} }
/**
function RSSTitle() { * @return string
return sprintf( */
_t('PageComment.COMMENTBY', "Comment by '%s' on %s", PR_MEDIUM, 'Name, Page Title'), public function getTitle() {
Convert::raw2xml($this->getRSSName()), $title = sprintf(_t('Comment.COMMENTBY', "Comment by '%s'", 'Name'), $this->getAuthorName());
$this->Parent()->Title
); if($parent = $this->getParent()) {
if($parent->Title) {
$title .= sprintf(" %s %s", _t('Comment.ON', 'on'), $parent->Title);
}
}
return $title;
} }
} }

View File

@ -15,7 +15,7 @@ class CommentsExtension extends DataExtension {
* *
* @return array * @return array
*/ */
function extraStatics($class = null, $extension = null) { public function extraStatics($class = null, $extension = null) {
$fields = array(); $fields = array();
$relationships = array( $relationships = array(
@ -99,9 +99,7 @@ class CommentsExtension extends DataExtension {
// do not include the comments on pages which don't have id's such as security pages // do not include the comments on pages which don't have id's such as security pages
if($this->owner->ID < 0) return false; if($this->owner->ID < 0) return false;
$controller = new CommentingController(); $controller = new CommentingController();
// tad bit messy but needed to ensure all data is available
$controller->setOwnerRecord($this->owner); $controller->setOwnerRecord($this->owner);
$controller->setBaseClass($this->ownerBaseClass); $controller->setBaseClass($this->ownerBaseClass);
$controller->setOwnerController(Controller::curr()); $controller->setOwnerController(Controller::curr());
@ -114,6 +112,8 @@ class CommentsExtension extends DataExtension {
'CommentHolderID' => Commenting::get_config_value($this->ownerBaseClass, 'comments_holder_id'), 'CommentHolderID' => Commenting::get_config_value($this->ownerBaseClass, 'comments_holder_id'),
'PostingRequiresPermission' => Commenting::get_config_value($this->ownerBaseClass, 'required_permission'), 'PostingRequiresPermission' => Commenting::get_config_value($this->ownerBaseClass, 'required_permission'),
'CanPost' => Commenting::can_member_post($this->ownerBaseClass), 'CanPost' => Commenting::can_member_post($this->ownerBaseClass),
'RssLink' => "CommentingController/rss",
'RssLinkPage' => "CommentingController/rss/". $this->ownerBaseClass . '/'.$this->owner->ID,
'CommentsEnabled' => $enabled, 'CommentsEnabled' => $enabled,
'AddCommentForm' => $form, 'AddCommentForm' => $form,
'Comments' => $this->Comments() 'Comments' => $this->Comments()
@ -134,7 +134,7 @@ class CommentsExtension extends DataExtension {
/** /**
* @deprecated 1.0 Please use {@link CommentsExtension->CommentsForm()} * @deprecated 1.0 Please use {@link CommentsExtension->CommentsForm()}
*/ */
function PageComments() { public function PageComments() {
// This method is very commonly used, don't throw a warning just yet // This method is very commonly used, don't throw a warning just yet
//user_error('$PageComments is deprecated. Please use $CommentsForm', E_USER_WARNING); //user_error('$PageComments is deprecated. Please use $CommentsForm', E_USER_WARNING);

View File

@ -1,32 +1,28 @@
<p class="comment" id="$Permalink"> <div class="comment" id="$Permalink">
<% if bbCodeEnabled %> <p>$Comment.XML</p>
$ParsedBBCode </div>
<% else %>
$Comment.XML
<% end_if %>
</p>
<p class="info"> <p class="info">
<% if $URL %> <% if $URL %>
<% _t('PBY','Posted by') %> <a href="$URL.URL" rel="nofollow">$Name.XML</a>, $Created.Nice ($Created.Ago) <% _t('PBY','Posted by') %> <a href="$URL.URL" rel="nofollow">$AuthorName.XML</a>, $Created.Nice ($Created.Ago)
<% else %> <% else %>
<% _t('PBY','Posted by') %> $Name.XML, $Created.Nice ($Created.Ago) <% _t('PBY','Posted by') %> $AuthorName.XML, $Created.Nice ($Created.Ago)
<% end_if %> <% end_if %>
</p> </p>
<% if ApproveLink || SpamLink || HamLink || DeleteLink %> <% if $ApproveLink || $SpamLink || $HamLink || $DeleteLink %>
<ul class="action-links"> <ul class="action-links">
<% if ApproveLink %> <% if ApproveLink %>
<li><a href="$ApproveLink" class="approve"><% _t('APPROVE', 'approve this comment') %></a></li> <li><a href="$ApproveLink.ATT" class="approve"><% _t('APPROVE', 'approve this comment') %></a></li>
<% end_if %> <% end_if %>
<% if SpamLink %> <% if SpamLink %>
<li><a href="$SpamLink" class="spam"><% _t('ISSPAM','this comment is spam') %></a></li> <li><a href="$SpamLink.ATT" class="spam"><% _t('ISSPAM','this comment is spam') %></a></li>
<% end_if %> <% end_if %>
<% if HamLink %> <% if HamLink %>
<li><a href="$HamLink" class="ham"><% _t('ISNTSPAM','this comment is not spam') %></a></li> <li><a href="$HamLink.ATT" class="ham"><% _t('ISNTSPAM','this comment is not spam') %></a></li>
<% end_if %> <% end_if %>
<% if DeleteLink %> <% if DeleteLink %>
<li class="last"><a href="$DeleteLink" class="delete"><% _t('REMCOM','remove this comment') %></a></li> <li class="last"><a href="$DeleteLink.ATT" class="delete"><% _t('REMCOM','remove this comment') %></a></li>
<% end_if %> <% end_if %>
</ul> </ul>
<% end_if %> <% end_if %>