ENHANCEMENT: allow comment area ids to be set in the configuration class allowing multiple forms on a single page. APICHANGE: migrated Comment::moderation() to the per type setting in the Commenting class

This commit is contained in:
Will Rossiter 2010-12-06 23:09:04 +13:00
parent d06a9a12bc
commit 92aa2afc0c
9 changed files with 118 additions and 255 deletions

View File

@ -24,11 +24,14 @@ class Commenting {
*/ */
private static $default_config = array( private static $default_config = array(
'require_login' => false, // boolean, whether a user needs to login 'require_login' => false, // boolean, whether a user needs to login
'required_permission' => '', // required permission to comment (or array of permissions) 'required_permission' => false, // required permission to comment (or array of permissions)
'use_ajax_commenting' => true, // use ajax to post comments. 'use_ajax_commenting' => true, // use ajax to post comments.
'show_comments_when_disabled' => false, // when comments are disabled should we show older comments (if available) 'show_comments_when_disabled' => false, // when comments are disabled should we show older comments (if available)
'order_comments_by' => "\"Created\" DESC", 'order_comments_by' => "\"Created\" DESC",
'comments_per_page' => 10 'comments_per_page' => 10,
'comments_holder_id' => "comments-holder", // id for the comments holder
'comment_permalink_prefix' => "comment-", // id prefix for each comment. If needed make this different
'require_moderation' => false
); );
/** /**
@ -46,7 +49,7 @@ class Commenting {
} }
self::$enabled_classes[$class] = $settings; self::$enabled_classes[$class] = $settings;
Object::add_extension($class, 'CommentsExtension'); Object::add_extension($class, 'CommentsExtension');
} }
@ -138,4 +141,25 @@ class Commenting {
return false; return false;
} }
/**
* Return whether a user can post on a given commenting instance
*
* @param string $class
*/
public static function can_member_post($class) {
$member = Member::currentUser();
try {
$login = self::get_config_value($class, 'require_login');
$permission = self::get_config_value($class, 'required_permission');
if($permission && !Permission::check($permission)) return false;
if($login && !$member) return false;
}
catch(Exception $e) {}
return true;
}
} }

View File

@ -12,15 +12,16 @@
* SSAkismet::setAPIKey('<your-key>'); * SSAkismet::setAPIKey('<your-key>');
* </code> * </code>
* *
* You can then view spam for a page by appending <i>?showspam=1</i> to the url, or use the {@link CommentAdmin} in the CMS. * You can then view spam for a page by appending ?showspam=1 to the url, or use the {@link CommentAdmin} in the CMS.
* *
* @see http://demo.silverstripe.com/blog Demo of SSAkismet in action * @see http://demo.silverstripe.com/blog Demo of SSAkismet in action
* *
* @package cms * @package comments
* @subpackage comments
*/ */
class SSAkismet extends Akismet { class SSAkismet extends Akismet {
private static $apiKey; private static $apiKey;
private static $saveSpam = true; private static $saveSpam = true;
static function setAPIKey($key) { static function setAPIKey($key) {
@ -43,4 +44,41 @@ class SSAkismet extends Akismet {
parent::__construct(Director::absoluteBaseURL(), self::$apiKey); parent::__construct(Director::absoluteBaseURL(), self::$apiKey);
} }
} }
?>
/**
* Adds the hooks required into posting a comment to check for spam
*
* @package comments
*/
class SSAkismetExtension extends Extension {
function onBeforePostComment(&$form) {
$data = $form->getData();
if(SSAkismet::isEnabled()) {
try {
$akismet = new SSAkismet();
$akismet->setCommentAuthor($data['Name']);
$akismet->setCommentContent($data['Comment']);
if($akismet->isCommentSpam()) {
if(SSAkismet::getSaveSpam()) {
$comment = Object::create('Comment');
$form->saveInto($comment);
$comment->setField("IsSpam", true);
$comment->write();
}
echo "<b>"._t('CommentingController.SPAMDETECTED', 'Spam detected!!') . "</b><br /><br />";
printf("If you believe this was in error, please email %s.", ereg_replace("@", " _(at)_", Email::getAdminEmail()));
echo "<br /><br />"._t('CommentingController.MSGYOUPOSTED', 'The message you posted was:'). "<br /><br />";
echo $data['Comment'];
return;
}
} catch (Exception $e) {
// Akismet didn't work, continue without spam check
}
}
}
}

View File

@ -1,59 +0,0 @@
<?php
/**
* Represents an interface for viewing and adding page comments
* Create one, passing the page discussed to the constructor. It can then be
* inserted into a template.
*
* @package comments
*/
class CommentInterface extends RequestHandler {
static $url_handlers = array(
'$Item!' => '$Item',
);
static $allowed_actions = array(
'PostCommentForm',
);
protected $controller, $methodName, $page;
/**
* Create a new page comment interface
* @param controller The controller that the interface is used on
* @param methodName The method to return this CommentInterface object
* @param page The page that we're commenting on
*/
function __construct($controller, $methodName, $page) {
$this->controller = $controller;
$this->methodName = $methodName;
$this->page = $page;
parent::__construct();
}
function Link() {
return Controller::join_links($this->controller->Link(), $this->methodName);
}
function PostCommentForm() {
return $form;
}
function CommentRssLink() {
return Director::absoluteBaseURL() . "Comment/rss?pageid=" . $this->page->ID;
}
/**
* A link to Comment_Controller.deleteallcomments() which deletes all
* comments on a page referenced by the url param pageid
*/
function DeleteAllLink() {
if(Permission::check('CMS_ACCESS_CommentAdmin')) {
return Director::absoluteBaseURL() . "Comment/deleteallcomments?pageid=" . $this->page->ID;
}
}
}

View File

@ -12,8 +12,8 @@ class Comment extends DataObject {
"Comment" => "Text", "Comment" => "Text",
"Email" => "Varchar(200)", "Email" => "Varchar(200)",
"URL" => "Varchar(255)", "URL" => "Varchar(255)",
"SessionID" => "Varchar(255)", "BaseClass" => "Varchar(200)",
"ParentClass" => "Varchar(200)" "Moderated" => "Boolean"
); );
static $has_one = array( static $has_one = array(
@ -42,8 +42,20 @@ class Comment extends DataObject {
* *
* @return string link to this comment. * @return string link to this comment.
*/ */
function Link() { function Link($action = "") {
return $this->Parent()->Link() . '#PageComment_'. $this->ID; return $this->Parent()->Link($action) . '#' . $this->Permalink();
}
/**
* Returns the permalink for this {@link Comment}. Inserted into
* the ID tag of the comment
*
* @return string
*/
function Permalink() {
$prefix = Commenting::get_config_value($this->ownerBaseClass, 'comment_permalink_prefix');
return $prefix . '-' . $id;
} }
function getRSSName() { function getRSSName() {
@ -107,14 +119,6 @@ class Comment extends DataObject {
return $this->Parent()->Title; return $this->Parent()->Title;
} }
static function enableModeration() {
self::$moderate = true;
}
static function moderationEnabled() {
return self::$moderate;
}
static function enableBBCode() { static function enableBBCode() {
self::$bbcode = true; self::$bbcode = true;
} }
@ -158,29 +162,11 @@ class Comment extends DataObject {
} }
/** /**
* This always returns true, and should be handled by {@link PageCommentInterface->CanPostComment()}. * @todo needs to compare to the new {@link Commenting} configuration API
* *
* @todo Integrate with PageCommentInterface::$comments_require_permission and $comments_require_login
*
* @param Member $member
* @return Boolean * @return Boolean
*/ */
function canCreate($member = null) { function canCreate($member = null) {
$member = Member::currentUser();
if(self::$comments_require_permission && $member && Permission::check(self::$comments_require_permission)) {
// Comments require a certain permission, and the user has the correct permission
return true;
} elseif(self::$comments_require_login && $member && !self::$comments_require_permission) {
// Comments only require that a member is logged in
return true;
} elseif(!self::$comments_require_permission && !self::$comments_require_login) {
// Comments don't require anything - anyone can add a comment
return true;
}
return false; return false;
} }

View File

@ -37,7 +37,7 @@ class CommentsExtension extends DataObjectDecorator {
); );
} }
} }
return array_merge($fields, $relationships); return array_merge($fields, $relationships);
} }
@ -49,9 +49,10 @@ class CommentsExtension extends DataObjectDecorator {
* @return DataObjectSet * @return DataObjectSet
*/ */
function Comments() { function Comments() {
return DataObject::get('Comment', "\"ParentID\" = '". $this->owner->ID ."' AND \"ParentClass\" = '". $this->ownerBaseClass ."'"); return DataObject::get('Comment', "\"ParentID\" = '". $this->owner->ID ."' AND \"BaseClass\" = '". $this->ownerBaseClass ."'");
} }
/** /**
* Comments interface for the front end. Includes the CommentAddForm and the composition * Comments interface for the front end. Includes the CommentAddForm and the composition
* of the comments display. * of the comments display.
@ -59,24 +60,36 @@ class CommentsExtension extends DataObjectDecorator {
* To customize the html see templates/CommentInterface.ss or extend this function with * To customize the html see templates/CommentInterface.ss or extend this function with
* your own extension. * your own extension.
* *
* @todo Cleanup the passing of all this state based functionality
*
* @see docs/en/Extending * @see docs/en/Extending
*/ */
public function CommentsForm() { public function CommentsForm() {
$interface = new SSViewer('CommentsInterface'); $interface = new SSViewer('CommentsInterface');
// detect whether we comments are enabled. By default if $CommentsForm is included // detect whether we comments are enabled. By default if $CommentsForm is included
// on a {@link DataObject} then it is enabled, however {@link SiteTree} objects can // on a {@link DataObject} then it is enabled, however {@link SiteTree} objects can
// trigger comments on / off via ProvideComments // trigger comments on / off via ProvideComments
$enabled = (!$this->attachedToSiteTree() || $this->owner->ProvideComments) ? true : false; $enabled = (!$this->attachedToSiteTree() || $this->owner->ProvideComments) ? true : false;
$controller = new CommentingController();
$form = ($enabled) ? new CommentForm(Controller::curr(), 'CommentsForm', $this->owner) : false; // tad bit messy but needed to ensure all datas available
$controller->setOwnerRecord($this->owner);
$controller->setBaseClass($this->ownerBaseClass);
$controller->setOwnerController(Controller::curr());
// if comments are turned off then $form = ($enabled) ? $controller->CommentsForm() : false;
// a little bit all over the show but to ensure a slightly easier upgrade for users
// return back the same variables as previously done in comments
return $interface->process(new ArrayData(array( return $interface->process(new ArrayData(array(
'CommentsEnabled' => $enabled, 'CommentHolderID' => Commenting::get_config_value($this->ownerBaseClass, 'comments_holder_id'),
'AddCommentForm' => $form, 'PostingRequiresPermission' => Commenting::get_config_value($this->ownerBaseClass, 'required_permission'),
'Comments' => $this->Comments() 'CanPost' => Commenting::can_member_post($this->ownerBaseClass),
'CommentsEnabled' => $enabled,
'AddCommentForm' => $form,
'Comments' => $this->Comments()
))); )));
} }

View File

@ -8,154 +8,16 @@
class CommentForm extends Form { class CommentForm extends Form {
private static $ownerClass = false;
/** /**
* Returns a create comment form * Returns a create comment form
* *
* @return Form * @return Form
*/ */
function __construct($controller, $name, $class) { function __construct($controller, $name) {
$member = Member::currentUser();
$class = (is_object($class)) ? $class->ClassName : $class;
$fields = new FieldSet();
if((Commenting::get_config_value($class, 'require_login')
|| Commenting::get_config_value($class, 'required_permission'))
&& ($member && $member->FirstName)) {
// note this was a ReadonlyField - which displayed the name in a span as well as the hidden field but
// it was not saving correctly. Have changed it to a hidden field. It passes the data correctly but I
// believe the id of the form field is wrong.
$fields->push(new ReadonlyField("NameView", _t('CommentInterface.YOURNAME', 'Your name'), $member->getName()));
$fields->push(new HiddenField("Name", "", $member->getName()));
} else {
$fields->push(new TextField("Name", _t('CommentInterface.YOURNAME', 'Your name')));
}
$fields->push(new TextField("URL", _t('CommentForm.COMMENTERURL', "Your website URL")));
$fields->push(new EmailField("Email", _t('CommentForm', "Your email address (will not be published)")));
$fields->push(new TextareaField("Comment", _t('CommentInterface.YOURCOMMENT', "Comments")));
$actions = new FieldSet(
new FormAction("doPostComment", _t('CommentInterface.POST', 'Post'))
);
// Set it so the user gets redirected back down to the form upon form fail
$this->setRedirectToFormOnValidationError(true);
// Required fields for server side
$required = new RequiredFields(array(
'Name',
'Email',
'Comment'
));
// load any data from the cookies
if($data = Cookie::get('CommentsForm_UserData')) {
$data = unserialize($data);
$form->loadDataFrom(array(
"Name" => isset($data['Name']) ? $data['Name'] : '',
"URL" => isset($data['URL']) ? $data['URL'] : '',
"Email" => isset($data['Email']) ? $data['Email'] : '',
"Comment" => Cookie::get('CommentsForm_Comment')
));
}
// hook to allow further extensions to alter the comments form
$this->extend('alterCommentForm', $form);
parent::__construct($controller, $name, $fields, $actions, $required);
} }
/**
* Process which creates a {@link Comment} once a user submits a comment from this form.
*
* @param array $data
* @param Form $form
*/
function doPostComment($data, $form) {
// cache users data
Cookie::set("CommentsForm_UserData", serialize($data));
Cookie::set("CommentsForm_Comment", $data['Comment']);
// @todo turn this into an extension
if(SSAkismet::isEnabled()) {
try {
$akismet = new SSAkismet();
$akismet->setCommentAuthor($data['Name']);
$akismet->setCommentContent($data['Comment']);
if($akismet->isCommentSpam()) {
if(SSAkismet::getSaveSpam()) {
$comment = Object::create('Comment');
$this->saveInto($comment);
$comment->setField("IsSpam", true);
$comment->write();
}
echo "<b>"._t('CommentInterface_Form.SPAMDETECTED', 'Spam detected!!') . "</b><br /><br />";
printf("If you believe this was in error, please email %s.", ereg_replace("@", " _(at)_", Email::getAdminEmail()));
echo "<br /><br />"._t('CommentInterface_Form.MSGYOUPOSTED', 'The message you posted was:'). "<br /><br />";
echo $data['Comment'];
return;
}
} catch (Exception $e) {
// Akismet didn't work, continue without spam check
}
}
// If commenting can only be done by logged in users, make sure the user is logged in
$member = Member::currentUser();
if(CommentInterface::CanPostComment() && $member) {
$this->Fields()->push(new HiddenField("AuthorID", "Author ID", $member->ID));
} elseif(!CommentInterface::CanPostComment()) {
echo "You're not able to post comments to this page. Please ensure you are logged in and have an appropriate permission level.";
return;
}
$comment = Object::create('Comment');
$this->saveInto($comment);
// @todo this should be in the onBeforeWrite of the comment. Via an extension
if($session = Session::get('mollom_user_session_id')) {
$comment->SessionID = $session;
Session::clear('mollom_user_session_id');
}
$comment->IsSpam = false;
$comment->NeedsModeration = Comment::moderationEnabled();
$comment->write();
$moderationMsg = _t('CommentInterface_Form.AWAITINGMODERATION', "Your comment has been submitted and is now awaiting moderation.");
// clear the users comment since it passed validation
Cookie::set('CommentsForm_Comment', false);
if(Director::is_ajax()) {
if($comment->NeedsModeration){
echo $moderationMsg;
} else{
echo $comment->renderWith('CommentInterface_singlecomment');
}
} else {
if($comment->NeedsModeration){
$this->sessionMessage($moderationMsg, 'good');
}
if($comment->ParentID) {
$page = DataObject::get_by_id("Page", $comment->ParentID);
if($page) {
// if it needs moderation then it won't appear in the list. Therefore
// we need to link to the comment holder rather than the individual comment
$url = ($comment->NeedsModeration) ? $page->Link() . '#Comments_holder' : $page->Link() . '#Comment_' . $comment->ID;
return $this->controller->redirect($url);
}
}
return $this->controller->redirectBack();
}
}
} }

View File

@ -15,8 +15,7 @@
* *
* See the Akismet class documentation page linked to below for usage information. * See the Akismet class documentation page linked to below for usage information.
* *
* @package cms * @package comments
* @subpackage comments
* @author Alex Potsides, {@link http://www.achingbrain.net http://www.achingbrain.net} * @author Alex Potsides, {@link http://www.achingbrain.net http://www.achingbrain.net}
* @version 0.1 * @version 0.1
* @copyright Alex Potsides, {@link http://www.achingbrain.net http://www.achingbrain.net} * @copyright Alex Potsides, {@link http://www.achingbrain.net http://www.achingbrain.net}

View File

@ -1,10 +1,10 @@
<% if CommentsEnabled %> <% if CommentsEnabled %>
<div id="PageComments_holder" class="typography"> <div id="$CommentHolderID">
<h4><% _t('POSTCOM','Post your comment') %></h4> <h4><% _t('POSTCOM','Post your comment') %></h4>
<% if AddCommentForm %> <% if AddCommentForm %>
<% if canPost %> <% if CanPost %>
$AddCommentForm $AddCommentForm
<% else %> <% else %>
<p><% _t('COMMENTLOGINERROR', 'You cannot post comments until you have logged in') %><% if PostingRequiresPermission %>,<% _t('COMMENTPERMISSIONERROR', 'and that you have an appropriate permission level') %><% end_if %>. <p><% _t('COMMENTLOGINERROR', 'You cannot post comments until you have logged in') %><% if PostingRequiresPermission %>,<% _t('COMMENTPERMISSIONERROR', 'and that you have an appropriate permission level') %><% end_if %>.
@ -17,9 +17,9 @@
<h4><% _t('COMMENTS','Comments') %></h4> <h4><% _t('COMMENTS','Comments') %></h4>
<div id="CommentHolder"> <div class="comments-holder">
<% if Comments %> <% if Comments %>
<ul id="PageComments"> <ul class="comments-list">
<% control Comments %> <% control Comments %>
<li class="$EvenOdd<% if FirstLast %> $FirstLast <% end_if %> $SpamClass"> <li class="$EvenOdd<% if FirstLast %> $FirstLast <% end_if %> $SpamClass">
<% include CommentsInterface_singlecomment %> <% include CommentsInterface_singlecomment %>

View File

@ -1,4 +1,4 @@
<p class="comment" id="PageComment_$ID"> <p class="comment" id="{$CommentPermalinkPrefix}-$ID">
<% if bbCodeEnabled %> <% if bbCodeEnabled %>
$ParsedBBCode $ParsedBBCode
<% else %> <% else %>