From 92aa2afc0cb354deed3009debd5e46cc86d16b93 Mon Sep 17 00:00:00 2001 From: Will Rossiter Date: Mon, 6 Dec 2010 23:09:04 +1300 Subject: [PATCH] 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 --- code/Commenting.php | 30 +++- code/SSAkismet.php | 46 +++++- code/controllers/CommentInterface.php | 59 -------- code/dataobjects/Comment.php | 50 +++---- code/extensions/CommentsExtension.php | 29 +++- code/forms/CommentForm.php | 146 +------------------ code/thirdparty/Akismet.php | 3 +- templates/CommentsInterface.ss | 8 +- templates/CommentsInterface_singlecomment.ss | 2 +- 9 files changed, 118 insertions(+), 255 deletions(-) delete mode 100755 code/controllers/CommentInterface.php diff --git a/code/Commenting.php b/code/Commenting.php index 5affa70..e2d7b07 100644 --- a/code/Commenting.php +++ b/code/Commenting.php @@ -24,11 +24,14 @@ class Commenting { */ private static $default_config = array( '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. 'show_comments_when_disabled' => false, // when comments are disabled should we show older comments (if available) '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; - + Object::add_extension($class, 'CommentsExtension'); } @@ -138,4 +141,25 @@ class Commenting { 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; + } } \ No newline at end of file diff --git a/code/SSAkismet.php b/code/SSAkismet.php index 60da63a..96cb012 100644 --- a/code/SSAkismet.php +++ b/code/SSAkismet.php @@ -12,15 +12,16 @@ * SSAkismet::setAPIKey(''); * * - * You can then view spam for a page by appending ?showspam=1 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 * - * @package cms - * @subpackage comments + * @package comments */ class SSAkismet extends Akismet { + private static $apiKey; + private static $saveSpam = true; static function setAPIKey($key) { @@ -43,4 +44,41 @@ class SSAkismet extends Akismet { parent::__construct(Director::absoluteBaseURL(), self::$apiKey); } } -?> \ No newline at end of file + +/** + * 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 ""._t('CommentingController.SPAMDETECTED', 'Spam detected!!') . "

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

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

"; + echo $data['Comment']; + + return; + } + } catch (Exception $e) { + // Akismet didn't work, continue without spam check + } + } + } +} \ No newline at end of file diff --git a/code/controllers/CommentInterface.php b/code/controllers/CommentInterface.php deleted file mode 100755 index 6041efd..0000000 --- a/code/controllers/CommentInterface.php +++ /dev/null @@ -1,59 +0,0 @@ - '$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; - } - } -} \ No newline at end of file diff --git a/code/dataobjects/Comment.php b/code/dataobjects/Comment.php index 82174d6..a9b9bed 100755 --- a/code/dataobjects/Comment.php +++ b/code/dataobjects/Comment.php @@ -12,8 +12,8 @@ class Comment extends DataObject { "Comment" => "Text", "Email" => "Varchar(200)", "URL" => "Varchar(255)", - "SessionID" => "Varchar(255)", - "ParentClass" => "Varchar(200)" + "BaseClass" => "Varchar(200)", + "Moderated" => "Boolean" ); static $has_one = array( @@ -42,8 +42,20 @@ class Comment extends DataObject { * * @return string link to this comment. */ - function Link() { - return $this->Parent()->Link() . '#PageComment_'. $this->ID; + function Link($action = "") { + 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() { @@ -107,14 +119,6 @@ class Comment extends DataObject { return $this->Parent()->Title; } - static function enableModeration() { - self::$moderate = true; - } - - static function moderationEnabled() { - return self::$moderate; - } - static function enableBBCode() { self::$bbcode = true; } @@ -158,29 +162,11 @@ class Comment extends DataObject { } /** - * This always returns true, and should be handled by {@link PageCommentInterface->CanPostComment()}. - * - * @todo Integrate with PageCommentInterface::$comments_require_permission and $comments_require_login - * - * @param Member $member + * @todo needs to compare to the new {@link Commenting} configuration API + * * @return Boolean */ 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; } diff --git a/code/extensions/CommentsExtension.php b/code/extensions/CommentsExtension.php index 0df980d..5b97710 100644 --- a/code/extensions/CommentsExtension.php +++ b/code/extensions/CommentsExtension.php @@ -37,7 +37,7 @@ class CommentsExtension extends DataObjectDecorator { ); } } - + return array_merge($fields, $relationships); } @@ -49,9 +49,10 @@ class CommentsExtension extends DataObjectDecorator { * @return DataObjectSet */ 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 * 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 * your own extension. * + * @todo Cleanup the passing of all this state based functionality + * * @see docs/en/Extending */ public function CommentsForm() { $interface = new SSViewer('CommentsInterface'); - // 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 $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( - 'CommentsEnabled' => $enabled, - 'AddCommentForm' => $form, - 'Comments' => $this->Comments() + 'CommentHolderID' => Commenting::get_config_value($this->ownerBaseClass, 'comments_holder_id'), + 'PostingRequiresPermission' => Commenting::get_config_value($this->ownerBaseClass, 'required_permission'), + 'CanPost' => Commenting::can_member_post($this->ownerBaseClass), + 'CommentsEnabled' => $enabled, + 'AddCommentForm' => $form, + 'Comments' => $this->Comments() ))); } diff --git a/code/forms/CommentForm.php b/code/forms/CommentForm.php index 8215d9b..2a1edff 100644 --- a/code/forms/CommentForm.php +++ b/code/forms/CommentForm.php @@ -8,154 +8,16 @@ class CommentForm extends Form { + private static $ownerClass = false; /** * Returns a create comment 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 ""._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(); - - $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(); - } - } + } diff --git a/code/thirdparty/Akismet.php b/code/thirdparty/Akismet.php index 5c68fce..5780500 100644 --- a/code/thirdparty/Akismet.php +++ b/code/thirdparty/Akismet.php @@ -15,8 +15,7 @@ * * See the Akismet class documentation page linked to below for usage information. * - * @package cms - * @subpackage comments + * @package comments * @author Alex Potsides, {@link http://www.achingbrain.net http://www.achingbrain.net} * @version 0.1 * @copyright Alex Potsides, {@link http://www.achingbrain.net http://www.achingbrain.net} diff --git a/templates/CommentsInterface.ss b/templates/CommentsInterface.ss index 758ecd6..3b64145 100755 --- a/templates/CommentsInterface.ss +++ b/templates/CommentsInterface.ss @@ -1,10 +1,10 @@ <% if CommentsEnabled %> -
+

<% _t('POSTCOM','Post your comment') %>

<% if AddCommentForm %> - <% if canPost %> + <% if CanPost %> $AddCommentForm <% else %>

<% _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 @@

<% _t('COMMENTS','Comments') %>

-
+
<% if Comments %> -
    +
      <% control Comments %>
    • <% include CommentsInterface_singlecomment %> diff --git a/templates/CommentsInterface_singlecomment.ss b/templates/CommentsInterface_singlecomment.ss index 97dc880..46e8557 100755 --- a/templates/CommentsInterface_singlecomment.ss +++ b/templates/CommentsInterface_singlecomment.ss @@ -1,4 +1,4 @@ -

      +

      <% if bbCodeEnabled %> $ParsedBBCode <% else %>