From 15a0dbc087b69a0d65546474827845541848f8a0 Mon Sep 17 00:00:00 2001 From: Will Rossiter Date: Tue, 30 Nov 2010 16:30:10 +1300 Subject: [PATCH] ENHANCEMENT: readded ProvideComments logic for comments when attached to site trees --- code/controllers/CommentInterface.php | 187 ++++---------------------- code/extensions/CommentsExtension.php | 60 ++++++++- code/forms/CommentForm.php | 137 +++++++++++++++++++ 3 files changed, 217 insertions(+), 167 deletions(-) create mode 100644 code/forms/CommentForm.php diff --git a/code/controllers/CommentInterface.php b/code/controllers/CommentInterface.php index 8b782ff..633aa00 100755 --- a/code/controllers/CommentInterface.php +++ b/code/controllers/CommentInterface.php @@ -1,13 +1,14 @@ '$Item', ); @@ -24,7 +25,7 @@ class CommentInterface extends RequestHandler { * * @var bool */ - static $comments_require_login = false; + private static $comments_require_login = false; /** * If this is a valid permission code, you must be logged in @@ -33,7 +34,7 @@ class CommentInterface extends RequestHandler { * * @var string */ - static $comments_require_permission = ""; + private static $comments_require_permission = ""; /** * If this is true it will include the javascript for AJAX @@ -42,7 +43,7 @@ class CommentInterface extends RequestHandler { * * @var bool */ - static $use_ajax_commenting = true; + private static $use_ajax_commenting = true; /** * If this is true then we should show the existing comments on @@ -51,9 +52,8 @@ class CommentInterface extends RequestHandler { * If this is false the form + existing comments will be hidden * * @var bool - * @since 2.4 - Always show them by default */ - static $show_comments_when_disabled = true; + private static $show_comments_when_disabled = true; /** * Define how you want to order page comments by. By default order by newest @@ -126,25 +126,28 @@ class CommentInterface extends RequestHandler { self::$use_ajax_commenting = $state; } - function forTemplate() { - return $this->renderWith('CommentInterface'); - } - /** * @return boolean true if the currently logged in user can post a comment, * false if they can't. Users can post comments by default, enforce * security by using + * * @link CommentInterface::set_comments_require_login() and * @link {CommentInterface::set_comments_require_permission()}. */ - static function CanPostComment() { + public static function canPost() { $member = Member::currentUser(); + if(self::$comments_require_permission && $member && Permission::check(self::$comments_require_permission)) { - return true; // Comments require a certain permission, and the user has the correct 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) { - return true; // Comments only require that a member is logged in + // Comments only require that a member is logged in + return true; + } elseif(!self::$comments_require_permission && !self::$comments_require_login) { - return true; // Comments don't require anything - anyone can add a comment + // Comments don't require anything - anyone can add a comment + return true; } return false; @@ -166,55 +169,8 @@ class CommentInterface extends RequestHandler { } function PostCommentForm() { - if(!$this->page->ProvideComments){ - return false; - } - $fields = new FieldSet( - new HiddenField("ParentID", "ParentID", $this->page->ID) - ); - - $member = Member::currentUser(); - - if((self::$comments_require_login || self::$comments_require_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'))); - } - - // optional commenter URL - $fields->push(new TextField("CommenterURL", _t('CommentInterface.COMMENTERURL', "Your website URL"))); - - if(MathSpamProtection::isEnabled()){ - $fields->push(new TextField("Math", sprintf(_t('CommentInterface.SPAMQUESTION', "Spam protection question: %s"), MathSpamProtection::getMathQuestion()))); - } - - $fields->push(new TextareaField("Comment", _t('CommentInterface.YOURCOMMENT', "Comments"))); - - $form = new CommentInterface_Form($this, "PostCommentForm", $fields, new FieldSet( - new FormAction("postcomment", _t('CommentInterface.POST', 'Post')) - )); - - // Set it so the user gets redirected back down to the form upon form fail - $form->setRedirectToFormOnValidationError(true); - - // Optional Spam Protection. - if(class_exists('SpamProtectorManager')) { - SpamProtectorManager::update_form($form, null, array('Name' => 'author_name', 'CommenterURL' => 'author_url', 'Comment' => 'post_body')); - self::set_use_ajax_commenting(false); - } - - // Shall We use AJAX? - if(self::$use_ajax_commenting) { - Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/behaviour/behaviour.js'); - Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/prototype/prototype.js'); - Requirements::javascript(THIRDPARTY_DIR . '/scriptaculous/effects.js'); - Requirements::javascript(CMS_DIR . '/javascript/CommentInterface.js'); - } - + + // Load the data from Session $form->loadDataFrom(array( "Name" => Cookie::get("CommentInterface_Name"), @@ -263,107 +219,14 @@ class CommentInterface extends RequestHandler { } /** - * @package cms - * @subpackage comments + * @package comments */ class CommentInterface_Form extends Form { - function postcomment($data) { - // Spam filtering - Cookie::set("CommentInterface_Name", $data['Name']); - Cookie::set("CommentInterface_CommenterURL", $data['CommenterURL']); - Cookie::set("CommentInterface_Comment", $data['Comment']); - - 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 ""._t('CommentInterface_Form.SPAMDETECTED', 'Spam detected!!') . "

"; - printf("If you believe this was in error, please email %s.", ereg_replace("@", " _(at)_", Email::getAdminEmail())); - echo "

"._t('CommentInterface_Form.MSGYOUPOSTED', 'The message you posted was:'). "

"; - echo $data['Comment']; - - return; - } - } catch (Exception $e) { - // Akismet didn't work, continue without spam check - } - } - - //check if spam question was right. - if(MathSpamProtection::isEnabled()){ - if(!MathSpamProtection::correctAnswer($data['Math'])){ - if(!Director::is_ajax()) { - Director::redirectBack(); - } - return "spamprotectionfailed"; //used by javascript for checking if the spam question was wrong - } - } - - // 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); - - // Store the Session ID if needed for Spamprotection - 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(); - - Cookie::set("CommentInterface_Comment", ''); - - $moderationMsg = _t('CommentInterface_Form.AWAITINGMODERATION', "Your comment has been submitted and is now awaiting moderation."); - - 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 Director::redirect($url); - } - } - - return Director::redirectBack(); - } - } + } /** - * @package cms - * @subpackage comments + * @package comments */ class CommentInterface_Controller extends ContentController { function __construct() { @@ -375,6 +238,4 @@ class CommentInterface_Controller extends ContentController { echo Convert::raw2xml(sprintf(_t('CommentInterface_Controller.SPAMQUESTION', "Spam protection question: %s"),MathSpamProtection::getMathQuestion())); } } -} - -?> +} \ No newline at end of file diff --git a/code/extensions/CommentsExtension.php b/code/extensions/CommentsExtension.php index 0d9d397..d43d4db 100644 --- a/code/extensions/CommentsExtension.php +++ b/code/extensions/CommentsExtension.php @@ -10,16 +10,35 @@ class CommentsExtension extends DataObjectDecorator { /** * Adds a relationship between this {@link DataObject} and its - * {@link Comment} objects + * {@link Comment} objects. If the owner class is a sitetree class + * it also enables a checkbox allowing comments to be turned off and off * * @return array */ function extraStatics() { - return array( + $fields = array(); + + $relationships = array( 'has_many' => array( 'Comments' => 'Comment' ) ); + + // if it is attached to the SiteTree then we need to add ProvideComments + // cannot check $this->owner as this in intialised via call_user_func + $args = func_get_args(); + + if($args && ($owner = array_shift($args))) { + if(ClassInfo::is_subclass_of($owner, 'SiteTree') || $owner == "SiteTree") { + $fields = array( + 'db' => array( + 'ProvideComments' => 'Boolean' + ) + ); + } + } + + return array_merge($fields, $relationships); } /** @@ -65,19 +84,52 @@ class CommentsExtension extends DataObjectDecorator { * * @see docs/en/Extending */ - function CommentsForm() { + public function CommentsForm() { $interface = new SSViewer('CommentsInterface'); return $interface->process(new ArrayData(array( + 'AddCommentForm' => $this->AddCommentForm(), 'Comments' => $this->Comments() ))); } + /** + * Add Comment Form. + * + * @see CommentForm + * @return Form|bool + */ + public function AddCommentForm() { + + // 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 + // trigger comments on / off via ProvideComments + if($this->attachedToSiteTree() && !$this->owner->ProvideComments) return false; + + $form = new CommentForm(Controller::curr(), 'CommentsForm'); + + // hook to allow further extensions to alter the comments form + $this->extend('alterAddCommentForm', $form); + + return $form; + } + + /** + * Returns whether this extension instance is attached to a {@link SiteTree} object + * + * @return bool + */ + public function attachedToSiteTree() { + return ClassInfo::is_subclass_of($this->ownerBaseClass, 'SiteTree'); + } + + + /** * @deprecated 1.0 Please use {@link CommentsExtension->CommentsForm()} */ function PageComments() { - user_error('$PageComments is deprecated. Please use $CommentsForm'); + user_error('$PageComments is deprecated. Please use $CommentsForm', E_USER_WARNING); return $this->CommentsForm(); } diff --git a/code/forms/CommentForm.php b/code/forms/CommentForm.php new file mode 100644 index 0000000..871a8ff --- /dev/null +++ b/code/forms/CommentForm.php @@ -0,0 +1,137 @@ +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 = new RequiredFields(); + + 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("CommentInterface_Name", $data['Name']); + Cookie::set("CommentInterface_CommenterURL", $data['CommenterURL']); + Cookie::set("CommentInterface_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 ""._t('CommentInterface_Form.SPAMDETECTED', 'Spam detected!!') . "

"; + printf("If you believe this was in error, please email %s.", ereg_replace("@", " _(at)_", Email::getAdminEmail())); + echo "

"._t('CommentInterface_Form.MSGYOUPOSTED', 'The message you posted was:'). "

"; + 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(); + + Cookie::set("CommentInterface_Comment", ''); + + $moderationMsg = _t('CommentInterface_Form.AWAITINGMODERATION', "Your comment has been submitted and is now awaiting moderation."); + + 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 Director::redirect($url); + } + } + + return Director::redirectBack(); + } + } + } +}