mirror of
https://github.com/silverstripe/silverstripe-comments
synced 2024-10-22 11:05:49 +02:00
Initial commit with transfer of existing comments functionality
This commit is contained in:
commit
a1df7f52df
17
LICENSE
Normal file
17
LICENSE
Normal file
@ -0,0 +1,17 @@
|
||||
Copyright (c) 2007-2010, SilverStripe Limited - www.silverstripe.com
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of SilverStripe nor the names of its contributors may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
21
README.md
Normal file
21
README.md
Normal file
@ -0,0 +1,21 @@
|
||||
# Comments
|
||||
|
||||
## Maintainers
|
||||
|
||||
* Will Rossiter (Nickname: willr, wrossiter)
|
||||
<will at silverstripe dot com>
|
||||
|
||||
## Introduction
|
||||
|
||||
This module provides a commenting functionality for Pages and other DataObjects. It replaces the built in
|
||||
commenting functionality with a more flexible plug and play version.
|
||||
|
||||
For more documentation about the module see the docs/ folder.
|
||||
|
||||
## Requirements
|
||||
|
||||
* SilverStripe 3.0 (SilverStripe Trunk as of Dec '10)
|
||||
|
||||
## Installation
|
||||
|
||||
See docs/en/Installing.md
|
321
code/CommentAdmin.php
Normal file
321
code/CommentAdmin.php
Normal file
@ -0,0 +1,321 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Comment administration system within the CMS
|
||||
*
|
||||
* @package comments
|
||||
*/
|
||||
class CommentAdmin extends LeftAndMain {
|
||||
|
||||
static $url_segment = 'comments';
|
||||
|
||||
static $url_rule = '/$Action';
|
||||
|
||||
static $menu_title = 'Comments';
|
||||
|
||||
static $allowed_actions = array(
|
||||
'approvedmarked',
|
||||
'deleteall',
|
||||
'deletemarked',
|
||||
'hammarked',
|
||||
'showtable',
|
||||
'spammarked',
|
||||
'EditForm',
|
||||
'unmoderated'
|
||||
);
|
||||
|
||||
/**
|
||||
* @var int The number of comments per page for the {@link CommentTable} in this admin.
|
||||
*/
|
||||
static $comments_per_page = '20';
|
||||
|
||||
public function init() {
|
||||
parent::init();
|
||||
|
||||
Requirements::javascript(CMS_DIR . '/javascript/CommentAdmin_right.js');
|
||||
Requirements::css(CMS_DIR . '/css/CommentAdmin.css');
|
||||
}
|
||||
|
||||
public function showtable($params) {
|
||||
return $this->getLastFormIn($this->renderWith('CommentAdmin_right'));
|
||||
}
|
||||
|
||||
public function Section() {
|
||||
$url = rtrim($_SERVER['REQUEST_URI'], '/');
|
||||
if(strrpos($url, '&')) {
|
||||
$url = substr($url, 0, strrpos($url, '&'));
|
||||
}
|
||||
$section = substr($url, strrpos($url, '/') + 1);
|
||||
|
||||
if($section != 'approved' && $section != 'unmoderated' && $section != 'spam') {
|
||||
$section = Session::get('CommentsSection');
|
||||
}
|
||||
|
||||
if($section != 'approved' && $section != 'unmoderated' && $section != 'spam') {
|
||||
$section = 'approved';
|
||||
}
|
||||
|
||||
return $section;
|
||||
}
|
||||
|
||||
public function EditForm() {
|
||||
$section = $this->Section();
|
||||
|
||||
if($section == 'approved') {
|
||||
$filter = "\"IsSpam\" = 0 AND \"NeedsModeration\" = 0";
|
||||
$title = "<h2>". _t('CommentAdmin.APPROVEDCOMMENTS', 'Approved Comments')."</h2>";
|
||||
} else if($section == 'unmoderated') {
|
||||
$filter = '"NeedsModeration" = 1';
|
||||
$title = "<h2>"._t('CommentAdmin.COMMENTSAWAITINGMODERATION', 'Comments Awaiting Moderation')."</h2>";
|
||||
} else {
|
||||
$filter = '"IsSpam" = 1';
|
||||
$title = "<h2>"._t('CommentAdmin.SPAM', 'Spam')."</h2>";
|
||||
}
|
||||
|
||||
$filter .= ' AND "ParentID">0';
|
||||
|
||||
$tableFields = array(
|
||||
"Name" => _t('CommentAdmin.AUTHOR', 'Author'),
|
||||
"Comment" => _t('CommentAdmin.COMMENT', 'Comment'),
|
||||
"Parent.Title" => _t('CommentAdmin.PAGE', 'Page'),
|
||||
"CommenterURL" => _t('CommentAdmin.COMMENTERURL', 'URL'),
|
||||
"Created" => _t('CommentAdmin.DATEPOSTED', 'Date Posted')
|
||||
);
|
||||
|
||||
$popupFields = new FieldSet(
|
||||
new TextField('Name', _t('CommentAdmin.NAME', 'Name')),
|
||||
new TextField('CommenterURL', _t('CommentAdmin.COMMENTERURL', 'URL')),
|
||||
new TextareaField('Comment', _t('CommentAdmin.COMMENT', 'Comment'))
|
||||
);
|
||||
|
||||
$idField = new HiddenField('ID', '', $section);
|
||||
$table = new CommentTableField($this, "Comments", "PageComment", $section, $tableFields, $popupFields, array($filter), 'Created DESC');
|
||||
|
||||
$table->setParentClass(false);
|
||||
$table->setFieldCasting(array(
|
||||
'Created' => 'SSDatetime->Full',
|
||||
'Comment' => array('HTMLText->LimitCharacters', 150)
|
||||
));
|
||||
|
||||
$table->setPageSize(self::get_comments_per_page());
|
||||
$table->addSelectOptions(array('all'=>'All', 'none'=>'None'));
|
||||
$table->Markable = true;
|
||||
|
||||
$fields = new FieldSet(
|
||||
new LiteralField("Title", $title),
|
||||
$idField,
|
||||
$table
|
||||
);
|
||||
|
||||
$actions = new FieldSet();
|
||||
|
||||
if($section == 'unmoderated') {
|
||||
$actions->push(new FormAction('acceptmarked', _t('CommentAdmin.ACCEPT', 'Accept')));
|
||||
}
|
||||
|
||||
if($section == 'approved' || $section == 'unmoderated') {
|
||||
$actions->push(new FormAction('spammarked', _t('CommentAdmin.SPAMMARKED', 'Mark as spam')));
|
||||
}
|
||||
|
||||
if($section == 'spam') {
|
||||
$actions->push(new FormAction('hammarked', _t('CommentAdmin.MARKASNOTSPAM', 'Mark as not spam')));
|
||||
}
|
||||
|
||||
$actions->push(new FormAction('deletemarked', _t('CommentAdmin.DELETE', 'Delete')));
|
||||
|
||||
if($section == 'spam') {
|
||||
$actions->push(new FormAction('deleteall', _t('CommentAdmin.DELETEALL', 'Delete All')));
|
||||
}
|
||||
|
||||
$form = new Form($this, "EditForm", $fields, $actions);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
function deletemarked() {
|
||||
$numComments = 0;
|
||||
$folderID = 0;
|
||||
$deleteList = '';
|
||||
|
||||
if($_REQUEST['Comments']) {
|
||||
foreach($_REQUEST['Comments'] as $commentid) {
|
||||
$comment = DataObject::get_by_id('PageComment', $commentid);
|
||||
if($comment) {
|
||||
$comment->delete();
|
||||
$numComments++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
user_error("No comments in $commentList could be found!", E_USER_ERROR);
|
||||
}
|
||||
|
||||
echo <<<JS
|
||||
$deleteList
|
||||
$('Form_EditForm').getPageFromServer($('Form_EditForm_ID').value);
|
||||
statusMessage("Deleted $numComments comments.");
|
||||
JS;
|
||||
}
|
||||
|
||||
function deleteall() {
|
||||
$numComments = 0;
|
||||
$spam = DataObject::get('PageComment', '"PageComment"."IsSpam" = 1');
|
||||
|
||||
if($spam) {
|
||||
$numComments = $spam->Count();
|
||||
|
||||
foreach($spam as $comment) {
|
||||
$comment->delete();
|
||||
}
|
||||
}
|
||||
|
||||
$msg = sprintf(_t('CommentAdmin.DELETED', 'Deleted %s comments.'), $numComments);
|
||||
echo <<<JS
|
||||
$('Form_EditForm').getPageFromServer($('Form_EditForm_ID').value);
|
||||
statusMessage("$msg");
|
||||
JS;
|
||||
|
||||
}
|
||||
|
||||
function spammarked() {
|
||||
$numComments = 0;
|
||||
$folderID = 0;
|
||||
$deleteList = '';
|
||||
|
||||
if($_REQUEST['Comments']) {
|
||||
foreach($_REQUEST['Comments'] as $commentid) {
|
||||
$comment = DataObject::get_by_id('PageComment', $commentid);
|
||||
if($comment) {
|
||||
$comment->IsSpam = true;
|
||||
$comment->NeedsModeration = false;
|
||||
$comment->write();
|
||||
|
||||
if(SSAkismet::isEnabled()) {
|
||||
try {
|
||||
$akismet = new SSAkismet();
|
||||
$akismet->setCommentAuthor($comment->getField('Name'));
|
||||
$akismet->setCommentContent($comment->getField('Comment'));
|
||||
|
||||
$akismet->submitSpam();
|
||||
} catch (Exception $e) {
|
||||
// Akismet didn't work, most likely the service is down.
|
||||
}
|
||||
}
|
||||
$numComments++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
user_error("No comments in $commentList could be found!", E_USER_ERROR);
|
||||
}
|
||||
|
||||
$msg = sprintf(_t('CommentAdmin.MARKEDSPAM', 'Marked %s comments as spam.'), $numComments);
|
||||
echo <<<JS
|
||||
$deleteList
|
||||
$('Form_EditForm').getPageFromServer($('Form_EditForm_ID').value);
|
||||
statusMessage("$msg");
|
||||
JS;
|
||||
}
|
||||
|
||||
function hammarked() {
|
||||
$numComments = 0;
|
||||
$folderID = 0;
|
||||
$deleteList = '';
|
||||
|
||||
if($_REQUEST['Comments']) {
|
||||
foreach($_REQUEST['Comments'] as $commentid) {
|
||||
$comment = DataObject::get_by_id('PageComment', $commentid);
|
||||
if($comment) {
|
||||
$comment->IsSpam = false;
|
||||
$comment->NeedsModeration = false;
|
||||
$comment->write();
|
||||
|
||||
if(SSAkismet::isEnabled()) {
|
||||
try {
|
||||
$akismet = new SSAkismet();
|
||||
$akismet->setCommentAuthor($comment->getField('Name'));
|
||||
$akismet->setCommentContent($comment->getField('Comment'));
|
||||
|
||||
$akismet->submitSpam();
|
||||
} catch (Exception $e) {
|
||||
// Akismet didn't work, most likely the service is down.
|
||||
}
|
||||
}
|
||||
|
||||
$numComments++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
user_error("No comments in $commentList could be found!", E_USER_ERROR);
|
||||
}
|
||||
|
||||
$msg = sprintf(_t('CommentAdmin.MARKEDNOTSPAM', 'Marked %s comments as not spam.'), $numComments);
|
||||
echo <<<JS
|
||||
$deleteList
|
||||
$('Form_EditForm').getPageFromServer($('Form_EditForm_ID').value);
|
||||
statusMessage("$msg");
|
||||
JS;
|
||||
}
|
||||
|
||||
function acceptmarked() {
|
||||
$numComments = 0;
|
||||
$folderID = 0;
|
||||
$deleteList = '';
|
||||
|
||||
if($_REQUEST['Comments']) {
|
||||
foreach($_REQUEST['Comments'] as $commentid) {
|
||||
$comment = DataObject::get_by_id('PageComment', $commentid);
|
||||
if($comment) {
|
||||
$comment->IsSpam = false;
|
||||
$comment->NeedsModeration = false;
|
||||
$comment->write();
|
||||
$numComments++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
user_error("No comments in $commentList could be found!", E_USER_ERROR);
|
||||
}
|
||||
|
||||
$msg = sprintf(_t('CommentAdmin.APPROVED', 'Accepted %s comments.'), $numComments);
|
||||
echo <<<JS
|
||||
$deleteList
|
||||
$('Form_EditForm').getPageFromServer($('Form_EditForm_ID').value);
|
||||
statusMessage("Accepted $numComments comments.");
|
||||
JS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of moderated comments
|
||||
*/
|
||||
function NumModerated() {
|
||||
return DB::query("SELECT COUNT(*) FROM \"PageComment\" WHERE \"IsSpam\"=0 AND \"NeedsModeration\"=0")->value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of unmoderated comments
|
||||
*/
|
||||
function NumUnmoderated() {
|
||||
return DB::query("SELECT COUNT(*) FROM \"PageComment\" WHERE \"IsSpam\"=0 AND \"NeedsModeration\"=1")->value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of comments marked as spam
|
||||
*/
|
||||
function NumSpam() {
|
||||
return DB::query("SELECT COUNT(*) FROM \"PageComment\" WHERE \"IsSpam\"=1")->value();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $num int
|
||||
*/
|
||||
function set_comments_per_page($num){
|
||||
self::$comments_per_page = $num;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
function get_comments_per_page(){
|
||||
return self::$comments_per_page;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
379
code/controllers/CommentInterface.php
Executable file
379
code/controllers/CommentInterface.php
Executable file
@ -0,0 +1,379 @@
|
||||
<?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 cms
|
||||
* @subpackage comments
|
||||
*/
|
||||
class PageCommentInterface extends RequestHandler {
|
||||
static $url_handlers = array(
|
||||
'$Item!' => '$Item',
|
||||
);
|
||||
static $allowed_actions = array(
|
||||
'PostCommentForm',
|
||||
);
|
||||
|
||||
protected $controller, $methodName, $page;
|
||||
|
||||
/**
|
||||
* If this is true, you must be logged in to post a comment
|
||||
* (and therefore, you don't need to specify a 'Your name' field unless
|
||||
* your name is blank)
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
static $comments_require_login = false;
|
||||
|
||||
/**
|
||||
* If this is a valid permission code, you must be logged in
|
||||
* and have the appropriate permission code on your account before you can
|
||||
* post a comment.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
static $comments_require_permission = "";
|
||||
|
||||
/**
|
||||
* If this is true it will include the javascript for AJAX
|
||||
* commenting. If it is set to false then it will not load
|
||||
* the files required and it will fall back
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
static $use_ajax_commenting = true;
|
||||
|
||||
/**
|
||||
* If this is true then we should show the existing comments on
|
||||
* the page even when we have disabled the comment form.
|
||||
*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Define how you want to order page comments by. By default order by newest
|
||||
* to oldest.
|
||||
*
|
||||
* @var String - used as $orderby in DB query
|
||||
* @since 2.4
|
||||
*/
|
||||
static $order_comments_by = "\"Created\" DESC";
|
||||
|
||||
/**
|
||||
* Create a new page comment interface
|
||||
* @param controller The controller that the interface is used on
|
||||
* @param methodName The method to return this PageCommentInterface 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link PageCommentInterface::$comments_require_login}
|
||||
*
|
||||
* @param boolean state The new state of this static field
|
||||
*/
|
||||
static function set_comments_require_login($state) {
|
||||
self::$comments_require_login = (boolean) $state;
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link PageCommentInterface::$comments_require_permission}
|
||||
*
|
||||
* @param string permission The permission to check against.
|
||||
*/
|
||||
static function set_comments_require_permission($permission) {
|
||||
self::$comments_require_permission = $permission;
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link PageCommentInterface::$show_comments_when_disabled}
|
||||
*
|
||||
* @param bool - show / hide the existing comments when disabled
|
||||
*/
|
||||
static function set_show_comments_when_disabled($state) {
|
||||
self::$show_comments_when_disabled = $state;
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link PageCommentInterface::$order_comments_by}
|
||||
*
|
||||
* @param String
|
||||
*/
|
||||
static function set_order_comments_by($order) {
|
||||
self::$order_comments_by = $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link PageCommentInterface::$use_ajax_commenting}
|
||||
*
|
||||
* @param bool
|
||||
*/
|
||||
static function set_use_ajax_commenting($state) {
|
||||
self::$use_ajax_commenting = $state;
|
||||
}
|
||||
|
||||
function forTemplate() {
|
||||
return $this->renderWith('PageCommentInterface');
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 PageCommentInterface::set_comments_require_login() and
|
||||
* @link {PageCommentInterface::set_comments_require_permission()}.
|
||||
*/
|
||||
static function CanPostComment() {
|
||||
$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
|
||||
} elseif(self::$comments_require_login && $member && !self::$comments_require_permission) {
|
||||
return true; // Comments only require that a member is logged in
|
||||
} elseif(!self::$comments_require_permission && !self::$comments_require_login) {
|
||||
return true; // Comments don't require anything - anyone can add a comment
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* if this page comment form requires users to have a
|
||||
* valid permission code in order to post (used to customize the error
|
||||
* message).
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function PostingRequiresPermission() {
|
||||
return self::$comments_require_permission;
|
||||
}
|
||||
|
||||
function Page() {
|
||||
return $this->page;
|
||||
}
|
||||
|
||||
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('PageCommentInterface.YOURNAME', 'Your name'), $member->getName()));
|
||||
$fields->push(new HiddenField("Name", "", $member->getName()));
|
||||
} else {
|
||||
$fields->push(new TextField("Name", _t('PageCommentInterface.YOURNAME', 'Your name')));
|
||||
}
|
||||
|
||||
// optional commenter URL
|
||||
$fields->push(new TextField("CommenterURL", _t('PageCommentInterface.COMMENTERURL', "Your website URL")));
|
||||
|
||||
if(MathSpamProtection::isEnabled()){
|
||||
$fields->push(new TextField("Math", sprintf(_t('PageCommentInterface.SPAMQUESTION', "Spam protection question: %s"), MathSpamProtection::getMathQuestion())));
|
||||
}
|
||||
|
||||
$fields->push(new TextareaField("Comment", _t('PageCommentInterface.YOURCOMMENT', "Comments")));
|
||||
|
||||
$form = new PageCommentInterface_Form($this, "PostCommentForm", $fields, new FieldSet(
|
||||
new FormAction("postcomment", _t('PageCommentInterface.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/PageCommentInterface.js');
|
||||
}
|
||||
|
||||
// Load the data from Session
|
||||
$form->loadDataFrom(array(
|
||||
"Name" => Cookie::get("PageCommentInterface_Name"),
|
||||
"Comment" => Cookie::get("PageCommentInterface_Comment"),
|
||||
"CommenterURL" => Cookie::get("PageCommentInterface_CommenterURL")
|
||||
));
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
function Comments() {
|
||||
// Comment limits
|
||||
$limit = array();
|
||||
$limit['start'] = isset($_GET['commentStart']) ? (int)$_GET['commentStart'] : 0;
|
||||
$limit['limit'] = PageComment::$comments_per_page;
|
||||
|
||||
$spamfilter = isset($_GET['showspam']) ? '' : "AND \"IsSpam\" = 0";
|
||||
$unmoderatedfilter = Permission::check('CMS_ACCESS_CommentAdmin') ? '' : "AND \"NeedsModeration\" = 0";
|
||||
$order = self::$order_comments_by;
|
||||
$comments = DataObject::get("PageComment", "\"ParentID\" = '" . Convert::raw2sql($this->page->ID) . "' $spamfilter $unmoderatedfilter", $order, "", $limit);
|
||||
|
||||
if(is_null($comments)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This allows us to use the normal 'start' GET variables as well (In the weird circumstance where you have paginated comments AND something else paginated)
|
||||
$comments->setPaginationGetVar('commentStart');
|
||||
|
||||
return $comments;
|
||||
}
|
||||
|
||||
function CommentRssLink() {
|
||||
return Director::absoluteBaseURL() . "PageComment/rss?pageid=" . $this->page->ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* A link to PageComment_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() . "PageComment/deleteallcomments?pageid=" . $this->page->ID;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @package cms
|
||||
* @subpackage comments
|
||||
*/
|
||||
class PageCommentInterface_Form extends Form {
|
||||
function postcomment($data) {
|
||||
// Spam filtering
|
||||
Cookie::set("PageCommentInterface_Name", $data['Name']);
|
||||
Cookie::set("PageCommentInterface_CommenterURL", $data['CommenterURL']);
|
||||
Cookie::set("PageCommentInterface_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('PageComment');
|
||||
$this->saveInto($comment);
|
||||
$comment->setField("IsSpam", true);
|
||||
$comment->write();
|
||||
}
|
||||
echo "<b>"._t('PageCommentInterface_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('PageCommentInterface_Form.MSGYOUPOSTED', 'The message you posted was:'). "<br /><br />";
|
||||
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(PageCommentInterface::CanPostComment() && $member) {
|
||||
$this->Fields()->push(new HiddenField("AuthorID", "Author ID", $member->ID));
|
||||
} elseif(!PageCommentInterface::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('PageComment');
|
||||
$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 = PageComment::moderationEnabled();
|
||||
$comment->write();
|
||||
|
||||
Cookie::set("PageCommentInterface_Comment", '');
|
||||
|
||||
$moderationMsg = _t('PageCommentInterface_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('PageCommentInterface_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() . '#PageComments_holder' : $page->Link() . '#PageComment_' . $comment->ID;
|
||||
|
||||
return Director::redirect($url);
|
||||
}
|
||||
}
|
||||
|
||||
return Director::redirectBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @package cms
|
||||
* @subpackage comments
|
||||
*/
|
||||
class PageCommentInterface_Controller extends ContentController {
|
||||
function __construct() {
|
||||
parent::__construct(null);
|
||||
}
|
||||
|
||||
function newspamquestion() {
|
||||
if(Director::is_ajax()) {
|
||||
echo Convert::raw2xml(sprintf(_t('PageCommentInterface_Controller.SPAMQUESTION', "Spam protection question: %s"),MathSpamProtection::getMathQuestion()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
228
code/dataobjects/Comment.php
Executable file
228
code/dataobjects/Comment.php
Executable file
@ -0,0 +1,228 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Represents a single comment object.
|
||||
*
|
||||
* @package comments
|
||||
*/
|
||||
class Comment extends DataObject {
|
||||
|
||||
static $db = array(
|
||||
"Name" => "Varchar(200)",
|
||||
"Comment" => "Text",
|
||||
"Email" => "Varchar(200)"
|
||||
"URL" => "Varchar(255)",
|
||||
"SessionID" => "Varchar(255)",
|
||||
);
|
||||
|
||||
static $has_one = array(
|
||||
"Parent" => "DataObject",
|
||||
"Author" => "Member"
|
||||
);
|
||||
|
||||
static $has_many = array();
|
||||
|
||||
static $many_many = array();
|
||||
|
||||
static $defaults = array();
|
||||
|
||||
static $casting = array(
|
||||
"RSSTitle" => "Varchar",
|
||||
);
|
||||
|
||||
static $comments_per_page = 10;
|
||||
|
||||
static $moderate = false;
|
||||
|
||||
static $bbcode = false;
|
||||
|
||||
/**
|
||||
* Return a link to this comment
|
||||
* @return string link to this comment.
|
||||
*/
|
||||
function Link() {
|
||||
return $this->Parent()->Link() . '#PageComment_'. $this->ID;
|
||||
}
|
||||
|
||||
function getRSSName() {
|
||||
if($this->Name) {
|
||||
return $this->Name;
|
||||
} elseif($this->Author()) {
|
||||
return $this->Author()->getName();
|
||||
}
|
||||
}
|
||||
|
||||
function ParsedBBCode(){
|
||||
$parser = new BBCodeParser($this->Comment);
|
||||
return $parser->parse();
|
||||
}
|
||||
|
||||
function DeleteLink() {
|
||||
return ($this->canDelete()) ? "PageComment_Controller/deletecomment/$this->ID" : false;
|
||||
}
|
||||
|
||||
function CommentTextWithLinks() {
|
||||
$pattern = '|([a-zA-Z]+://)([a-zA-Z0-9?&%.;:/=+_-]*)|is';
|
||||
$replace = '<a rel="nofollow" href="$1$2">$1$2</a>';
|
||||
return preg_replace($pattern, $replace, $this->Comment);
|
||||
}
|
||||
|
||||
function SpamLink() {
|
||||
return ($this->canEdit() && !$this->IsSpam) ? "PageComment_Controller/reportspam/$this->ID" : false;
|
||||
}
|
||||
|
||||
function HamLink() {
|
||||
return ($this->canEdit() && $this->IsSpam) ? "PageComment_Controller/reportham/$this->ID" : false;
|
||||
}
|
||||
|
||||
function ApproveLink() {
|
||||
return ($this->canEdit() && $this->NeedsModeration) ? "PageComment_Controller/approve/$this->ID" : false;
|
||||
}
|
||||
|
||||
function SpamClass() {
|
||||
if($this->getField('IsSpam')) {
|
||||
return 'spam';
|
||||
} else if($this->getField('NeedsModeration')) {
|
||||
return 'unmoderated';
|
||||
} else {
|
||||
return 'notspam';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function RSSTitle() {
|
||||
return sprintf(
|
||||
_t('PageComment.COMMENTBY', "Comment by '%s' on %s", PR_MEDIUM, 'Name, Page Title'),
|
||||
Convert::raw2xml($this->getRSSName()),
|
||||
$this->Parent()->Title
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function PageTitle() {
|
||||
return $this->Parent()->Title;
|
||||
}
|
||||
|
||||
static function enableModeration() {
|
||||
self::$moderate = true;
|
||||
}
|
||||
|
||||
static function moderationEnabled() {
|
||||
return self::$moderate;
|
||||
}
|
||||
|
||||
static function enableBBCode() {
|
||||
self::$bbcode = true;
|
||||
}
|
||||
|
||||
static function bbCodeEnabled() {
|
||||
return self::$bbcode;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param boolean $includerelations a boolean value to indicate if the labels returned include relation fields
|
||||
*
|
||||
*/
|
||||
function fieldLabels($includerelations = true) {
|
||||
$labels = parent::fieldLabels($includerelations);
|
||||
$labels['Name'] = _t('PageComment.Name', 'Author Name');
|
||||
$labels['Comment'] = _t('PageComment.Comment', 'Comment');
|
||||
$labels['IsSpam'] = _t('PageComment.IsSpam', 'Spam?');
|
||||
$labels['NeedsModeration'] = _t('PageComment.NeedsModeration', 'Needs Moderation?');
|
||||
|
||||
return $labels;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called just before this object is
|
||||
* written to the database.
|
||||
*
|
||||
* Specifically, make sure "http://" exists at the start
|
||||
* of the URL, if it doesn't have https:// or http://
|
||||
*/
|
||||
public function onBeforeWrite() {
|
||||
parent::onBeforeWrite();
|
||||
|
||||
$url = $this->CommenterURL;
|
||||
|
||||
if($url) {
|
||||
if(strtolower(substr($url, 0, 8)) != 'https://' && strtolower(substr($url, 0, 7)) != 'http://') {
|
||||
$this->CommenterURL = 'http://' . $url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @return Boolean
|
||||
*/
|
||||
function canCreate($member = null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for association with a page,
|
||||
* and {@link SiteTree->ProvidePermission} flag being set to TRUE.
|
||||
* Note: There's an additional layer of permission control
|
||||
* in {@link PageCommentInterface}.
|
||||
*
|
||||
* @param Member $member
|
||||
* @return Boolean
|
||||
*/
|
||||
function canView($member = null) {
|
||||
if(!$member) $member = Member::currentUser();
|
||||
|
||||
// Standard mechanism for accepting permission changes from decorators
|
||||
$extended = $this->extendedCan('canView', $member);
|
||||
if($extended !== null) return $extended;
|
||||
|
||||
$page = $this->Parent();
|
||||
return (
|
||||
($page && $page->ProvideComments)
|
||||
|| (bool)Permission::checkMember($member, 'CMS_ACCESS_CommentAdmin')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for "CMS_ACCESS_CommentAdmin" permission codes
|
||||
* and {@link canView()}.
|
||||
*
|
||||
* @param Member $member
|
||||
* @return Boolean
|
||||
*/
|
||||
function canEdit($member = null) {
|
||||
if(!$member) $member = Member::currentUser();
|
||||
|
||||
// Standard mechanism for accepting permission changes from decorators
|
||||
$extended = $this->extendedCan('canEdit', $member);
|
||||
if($extended !== null) return $extended;
|
||||
|
||||
if(!$this->canView($member)) return false;
|
||||
|
||||
return (bool)Permission::checkMember($member, 'CMS_ACCESS_CommentAdmin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for "CMS_ACCESS_CommentAdmin" permission codes
|
||||
* and {@link canEdit()}.
|
||||
*
|
||||
* @param Member $member
|
||||
* @return Boolean
|
||||
*/
|
||||
function canDelete($member = null) {
|
||||
if(!$member) $member = Member::currentUser();
|
||||
|
||||
// Standard mechanism for accepting permission changes from decorators
|
||||
$extended = $this->extendedCan('canDelete', $member);
|
||||
if($extended !== null) return $extended;
|
||||
|
||||
return $this->canEdit($member);
|
||||
}
|
||||
}
|
16
code/extensions/CommentExtension.php
Normal file
16
code/extensions/CommentExtension.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package comments
|
||||
*/
|
||||
|
||||
class CommentExtension extends DataObjectDecorator {
|
||||
|
||||
function Comments() {
|
||||
return DataObject::get('Comment', "\"RecordClassID\" = '". $this->owner->ID ."' AND \"RecordClass\" = '". $this->ownerBaseClass ."'");
|
||||
}
|
||||
|
||||
function CommentsForm() {
|
||||
die();
|
||||
}
|
||||
}
|
107
code/formfields/CommentTableField.php
Normal file
107
code/formfields/CommentTableField.php
Normal file
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
/**
|
||||
* Special kind of ComplexTableField for managing comments.
|
||||
*
|
||||
* @package comments
|
||||
*/
|
||||
class CommentTableField extends ComplexTableField {
|
||||
protected $template = "CommentTableField";
|
||||
protected $mode;
|
||||
|
||||
function __construct($controller, $name, $sourceClass, $mode, $fieldList, $detailFormFields = null, $sourceFilter = "", $sourceSort = "Created", $sourceJoin = "") {
|
||||
$this->mode = $mode;
|
||||
|
||||
Session::set('CommentsSection', $mode);
|
||||
|
||||
parent::__construct($controller, $name, $sourceClass, $fieldList, $detailFormFields, $sourceFilter, $sourceSort, $sourceJoin);
|
||||
|
||||
$this->Markable = true;
|
||||
|
||||
// Note: These keys have special behaviour associated through TableListField.js
|
||||
$this->selectOptions = array(
|
||||
'all' => _t('CommentTableField.SELECTALL', 'All'),
|
||||
'none' => _t('CommentTableField.SELECTNONE', 'None')
|
||||
);
|
||||
|
||||
// search
|
||||
$search = isset($_REQUEST['CommentSearch']) ? Convert::raw2sql($_REQUEST['CommentSearch']) : null;
|
||||
if(!empty($_REQUEST['CommentSearch'])) {
|
||||
$this->sourceFilter[] = "( \"Name\" LIKE '%$search%' OR \"Comment\" LIKE '%$search%')";
|
||||
}
|
||||
}
|
||||
|
||||
function FieldHolder() {
|
||||
$ret = parent::FieldHolder();
|
||||
|
||||
Requirements::javascript(CMS_DIR . '/javascript/CommentTableField.js');
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function Items() {
|
||||
$this->sourceItems = $this->sourceItems();
|
||||
|
||||
if(!$this->sourceItems) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$pageStart = (isset($_REQUEST['ctf'][$this->Name()]['start']) && is_numeric($_REQUEST['ctf'][$this->Name()]['start'])) ? $_REQUEST['ctf'][$this->Name()]['start'] : 0;
|
||||
$this->sourceItems->setPageLimits($pageStart, $this->pageSize, $this->totalCount);
|
||||
|
||||
$output = new DataObjectSet();
|
||||
foreach($this->sourceItems as $pageIndex=>$item) {
|
||||
$output->push(Object::create('CommentTableField_Item',$item, $this, $pageStart+$pageIndex));
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
function HasSpamButton() {
|
||||
return $this->mode == 'approved' || $this->mode == 'unmoderated';
|
||||
}
|
||||
|
||||
function HasApproveButton() {
|
||||
return $this->mode == 'unmoderated';
|
||||
}
|
||||
|
||||
function HasHamButton() {
|
||||
return $this->mode == 'spam';
|
||||
}
|
||||
|
||||
function SearchForm() {
|
||||
$query = isset($_GET['CommentSearch']) ? $_GET['CommentSearch'] : null;
|
||||
|
||||
$searchFields = new FieldGroup(
|
||||
new TextField('CommentSearch', _t('CommentTableField.SEARCH', 'Search'), $query),
|
||||
new HiddenField("ctf[ID]",'',$this->mode),
|
||||
new HiddenField('CommentFieldName','',$this->name)
|
||||
);
|
||||
|
||||
$actionFields = new LiteralField('CommentFilterButton','<input type="submit" name="CommentFilterButton" value="'. _t('CommentTableField.FILTER', 'Filter') .'" id="CommentFilterButton"/>');
|
||||
|
||||
$fieldContainer = new FieldGroup(
|
||||
$searchFields,
|
||||
$actionFields
|
||||
);
|
||||
|
||||
return $fieldContainer->FieldHolder();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Single row of a {@link CommentTableField}
|
||||
*
|
||||
* @package comments
|
||||
*/
|
||||
class CommentTableField_Item extends ComplexTableField_Item {
|
||||
function HasSpamButton() {
|
||||
return $this->parent()->HasSpamButton();
|
||||
}
|
||||
|
||||
function HasApproveButton() {
|
||||
return $this->parent()->HasApproveButton();
|
||||
}
|
||||
|
||||
function HasHamButton() {
|
||||
return $this->parent()->HasHamButton();
|
||||
}
|
||||
}
|
246
javascript/CommentsInterface.js
Executable file
246
javascript/CommentsInterface.js
Executable file
@ -0,0 +1,246 @@
|
||||
/**
|
||||
* Ajax to support the comment posting system
|
||||
*/
|
||||
|
||||
PageCommentInterface = Class.create();
|
||||
|
||||
PageCommentInterface.prototype = {
|
||||
initialize: function() {
|
||||
Behaviour.register({
|
||||
'#PageCommentInterface_Form_PostCommentForm_action_postcomment' : {
|
||||
onclick : this.postComment
|
||||
},
|
||||
|
||||
'#PageComments a.deletelink' : {
|
||||
onclick : this.deleteComment
|
||||
},
|
||||
'#PageComments a.spamlink' : {
|
||||
onclick : this.reportSpam
|
||||
},
|
||||
'#PageComments a.hamlink' : {
|
||||
onclick : this.reportHam
|
||||
},
|
||||
'#PageComments a.approvelink' : {
|
||||
onclick : this.approveComment
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
loadSpamQuestion: function(response) {
|
||||
var spamQuestionDiv = $('Math');
|
||||
var mathLabel = spamQuestionDiv.getElementsByTagName('label')[0];
|
||||
mathLabel.innerHTML = response.responseText;
|
||||
var mathQuestion = spamQuestionDiv.getElementsByTagName('input')[0];
|
||||
mathQuestion.value = '';
|
||||
},
|
||||
|
||||
postComment: function() {
|
||||
var form = $("PageCommentInterface_Form_PostCommentForm");
|
||||
var message = $("PageCommentInterface_Form_PostCommentForm_error");
|
||||
|
||||
if(form.elements.Name.value && form.elements.Comment.value) {
|
||||
if(noComments = $('NoComments')) {
|
||||
Element.remove(noComments);
|
||||
var pageComments = document.createElement('ul');
|
||||
pageComments.id = 'PageComments';
|
||||
$('CommentHolder').appendChild(pageComments);
|
||||
}
|
||||
|
||||
message.style.display = 'none';
|
||||
|
||||
// Create a new <li> for the post
|
||||
var pageComments = $('PageComments').getElementsByTagName('li');
|
||||
var __newComment = document.createElement('li');
|
||||
|
||||
|
||||
// Add it to the list with a 'loading' message
|
||||
$('PageComments').insertBefore(__newComment, pageComments[0]);
|
||||
__newComment.innerHTML = '<p><img src="cms/images/network-save.gif" /> Loading...</p>';
|
||||
|
||||
|
||||
// Submit the form via ajax
|
||||
Ajax.SubmitForm(form, "action_postcomment", {
|
||||
onSuccess : function(response) {
|
||||
|
||||
// Create an Ajax request to regenerate the spam protection question
|
||||
//need to check if there is actually a spam question to change first
|
||||
if(form.elements.Math){
|
||||
new Ajax.Request(document.getElementsByTagName('base')[0].href+'PageCommentInterface_Controller/newspamquestion', {
|
||||
onSuccess: loadSpamQuestion,
|
||||
onFailure: Ajax.Evaluator
|
||||
});
|
||||
}
|
||||
|
||||
if(response.responseText != "spamprotectionfailed"){
|
||||
__newComment.className ="even";
|
||||
// Load the response into the new <li>
|
||||
__newComment.innerHTML = response.responseText;
|
||||
Behaviour.apply(__newComment);
|
||||
|
||||
// Flash it using Scriptaculous
|
||||
new Effect.Highlight(__newComment, { endcolor: '#e9e9e9' } );
|
||||
if(response.responseText.match('<b>Spam detected!!</b>')) {
|
||||
__newComment.className = 'spam';
|
||||
}
|
||||
|
||||
}else{
|
||||
__newComment.innerHTML = "";
|
||||
Behaviour.apply(__newComment);
|
||||
message.style.display = '';
|
||||
message.innerHTML = "You got the spam question wrong.";
|
||||
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
onFailure : function(response) {
|
||||
alert(response.responseText);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
message.style.display = '';
|
||||
message.innerHTML = "Please enter your name and a comment to be posted to the site.";
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Ajax handler of moderation removal
|
||||
*/
|
||||
deleteComment: function() {
|
||||
var __comment = this.parentNode.parentNode.parentNode;
|
||||
|
||||
__comment.getElementsByTagName('span')[0].innerHTML = "Removing...";
|
||||
|
||||
new Ajax.Request(this.href + '?ajax=1', {
|
||||
onSuccess : function(response) {
|
||||
// Clear our wee status message
|
||||
__comment.getElementsByTagName('span')[0].innerHTML = "Removing...";
|
||||
|
||||
// Remove it using Scriptaculous
|
||||
new Effect.Highlight(__comment, {
|
||||
startcolor: '#cc9999' , endcolor: '#e9e9e9', duration: 0.5,
|
||||
afterFinish : function () {
|
||||
var commentList = __comment.parentNode;
|
||||
commentList.removeChild(__comment);
|
||||
if(!commentList.firstChild) {
|
||||
$('CommentHolder').innerHTML = "<p id=\"NoComments\">No one has commented on this page yet.</p>";
|
||||
}
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
onFailure : function(response) {
|
||||
alert(response.responseText);
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Ajax handler of spam reporting
|
||||
*/
|
||||
reportSpam: function() {
|
||||
var __comment = this.parentNode.parentNode.parentNode.parentNode;
|
||||
|
||||
__comment.getElementsByTagName('span')[0].innerHTML = "Reporting spam...";
|
||||
|
||||
|
||||
new Ajax.Request(this.href + '?ajax=1', {
|
||||
onSuccess : function(response) {
|
||||
if(response.responseText != '') {
|
||||
// Load the response into the <li>
|
||||
__comment.innerHTML = response.responseText;
|
||||
Behaviour.apply(__comment);
|
||||
|
||||
// Flash it using Scriptaculous
|
||||
new Effect.Highlight(__comment, { endcolor: '#cc9999' } );
|
||||
|
||||
__comment.className = 'spam';
|
||||
} else {
|
||||
new Effect.Highlight(__comment, {
|
||||
startcolor: '#cc9999' , endcolor: '#e9e9e9', duration: 0.5,
|
||||
afterFinish : function() {
|
||||
var commentList = __comment.parentNode;
|
||||
commentList.removeChild(__comment);
|
||||
if(!commentList.firstChild) {
|
||||
$('CommentHolder').innerHTML = "<p id=\"NoComments\">No one has commented on this page yet.</p>";
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
},
|
||||
|
||||
onFailure : function(response) {
|
||||
alert(response.responseText);
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Ajax handler of ham reporting
|
||||
*/
|
||||
reportHam: function() {
|
||||
var __comment = this.parentNode.parentNode.parentNode.parentNode;
|
||||
|
||||
__comment.getElementsByTagName('span')[0].innerHTML = "Reporting as not spam...";
|
||||
|
||||
new Ajax.Request(this.href + '?ajax=1', {
|
||||
onSuccess : function(response) {
|
||||
// Load the response into the <li>
|
||||
__comment.innerHTML = response.responseText;
|
||||
Behaviour.apply(__comment);
|
||||
|
||||
// Flash it using Scriptaculous
|
||||
new Effect.Highlight(__comment, { endcolor: '#e9e9e9' } );
|
||||
__comment.className = 'notspam';
|
||||
},
|
||||
|
||||
onFailure : function(response) {
|
||||
alert(response.responseText);
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Ajax handler of ham reporting
|
||||
*/
|
||||
approveComment: function() {
|
||||
var __comment = this.parentNode.parentNode.parentNode.parentNode;
|
||||
|
||||
__comment.getElementsByTagName('span')[0].innerHTML = "Marking comment as approved...";
|
||||
|
||||
new Ajax.Request(this.href + '?ajax=1', {
|
||||
onSuccess : function(response) {
|
||||
// Load the response into the <li>
|
||||
__comment.innerHTML = response.responseText;
|
||||
Behaviour.apply(__comment);
|
||||
|
||||
// Flash it using Scriptaculous
|
||||
new Effect.Highlight(__comment, { endcolor: '#e9e9e9' } );
|
||||
__comment.className = 'notspam';
|
||||
},
|
||||
|
||||
onFailure : function(response) {
|
||||
alert(response.responseText);
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
PageCommentInterface.applyTo("#PageComments_holder");
|
||||
function loadSpamQuestion(response) {
|
||||
var spamQuestionDiv = $('Math');
|
||||
var mathLabel = spamQuestionDiv.getElementsByTagName('label')[0];
|
||||
mathLabel.innerHTML = response.responseText;
|
||||
var mathQuestion = spamQuestionDiv.getElementsByTagName('input')[0];
|
||||
mathQuestion.value = '';
|
||||
}
|
65
templates/PageCommentInterface.ss
Executable file
65
templates/PageCommentInterface.ss
Executable file
@ -0,0 +1,65 @@
|
||||
<div id="PageComments_holder" class="typography">
|
||||
|
||||
<h4><% _t('POSTCOM','Post your comment') %></h4>
|
||||
<% if PostCommentForm %>
|
||||
<% if CanPostComment %>
|
||||
$PostCommentForm
|
||||
<% 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 %>.
|
||||
<a href="Security/login?BackURL={$Page.Link}" title="Login to post a comment"><% _t('COMMENTPOSTLOGIN', 'Login Here') %></a>.
|
||||
</p>
|
||||
<% end_if %>
|
||||
<% else %>
|
||||
<p><% _t('COMMENTSDISABLED', 'Posting comments has been disabled') %>.</p>
|
||||
<% end_if %>
|
||||
|
||||
<h4><% _t('COMMENTS','Comments') %></h4>
|
||||
|
||||
<div id="CommentHolder">
|
||||
<% if Comments %>
|
||||
<ul id="PageComments">
|
||||
<% control Comments %>
|
||||
<li class="$EvenOdd<% if FirstLast %> $FirstLast <% end_if %> $SpamClass">
|
||||
<% include PageCommentInterface_singlecomment %>
|
||||
</li>
|
||||
<% end_control %>
|
||||
</ul>
|
||||
|
||||
<% if Comments.MoreThanOnePage %>
|
||||
<div id="PageCommentsPagination">
|
||||
<p>
|
||||
<% if Comments.PrevLink %>
|
||||
<a href="$Comments.PrevLink">« <% _t('PREV','previous') %></a>
|
||||
<% end_if %>
|
||||
|
||||
<% if Comments.Pages %>
|
||||
<% control Comments.Pages %>
|
||||
<% if CurrentBool %>
|
||||
<strong>$PageNum</strong>
|
||||
<% else %>
|
||||
<a href="$Link">$PageNum</a>
|
||||
<% end_if %>
|
||||
<% end_control %>
|
||||
<% end_if %>
|
||||
|
||||
<% if Comments.NextLink %>
|
||||
<a href="$Comments.NextLink"><% _t('NEXT','next') %> »</a>
|
||||
<% end_if %>
|
||||
</p>
|
||||
</div>
|
||||
<% end_if %>
|
||||
<% else %>
|
||||
<p id="NoComments"><% _t('NOCOMMENTSYET','No one has commented on this page yet.') %></p>
|
||||
<% end_if %>
|
||||
</div>
|
||||
<% if DeleteAllLink %>
|
||||
<p id="DeleteComments"><a href="$DeleteAllLink">
|
||||
<% _t('PageCommentInterface.DELETEALLCOMMENTS','Delete all comments on this page') %>
|
||||
</a></p>
|
||||
<% end_if %>
|
||||
<p id="CommentsRSSFeed">
|
||||
<a class="commentrss" href="$CommentRssLink"><% _t('RSSFEEDCOMMENTS', 'RSS feed for comments on this page') %></a> |
|
||||
<a href="PageComment/rss" class="commentrss" title="<% _t('RSSVIEWALLCOMMENTS', 'View all Comments') %>"><% _t('RSSFEEDALLCOMMENTS', 'RSS feed for all comments') %></a>
|
||||
</p>
|
||||
</div>
|
||||
|
29
templates/PageCommentInterface_singlecomment.ss
Executable file
29
templates/PageCommentInterface_singlecomment.ss
Executable file
@ -0,0 +1,29 @@
|
||||
<p class="comment" id="PageComment_$ID">
|
||||
<% if bbCodeEnabled %>
|
||||
$ParsedBBCode
|
||||
<% else %>
|
||||
$Comment.XML
|
||||
<% end_if %>
|
||||
</p>
|
||||
<p class="info">
|
||||
<% if CommenterURL %>
|
||||
<% _t('PBY','Posted by') %> <a href="$CommenterURL.ATT">$Name.XML</a>, $Created.Nice ($Created.Ago)
|
||||
<% else %>
|
||||
<% _t('PBY','Posted by') %> $Name.XML, $Created.Nice ($Created.Ago)
|
||||
<% end_if %>
|
||||
</p>
|
||||
|
||||
<ul class="actionLinks">
|
||||
<% if ApproveLink %>
|
||||
<li><a href="$ApproveLink" class="approvelink"><% _t('APPROVE', 'approve this comment') %></a></li>
|
||||
<% end_if %>
|
||||
<% if SpamLink %>
|
||||
<li><a href="$SpamLink" class="spamlink"><% _t('ISSPAM','this comment is spam') %></a></li>
|
||||
<% end_if %>
|
||||
<% if HamLink %>
|
||||
<li><a href="$HamLink" class="hamlink"><% _t('ISNTSPAM','this comment is not spam') %></a></li>
|
||||
<% end_if %>
|
||||
<% if DeleteLink %>
|
||||
<li class="last"><a href="$DeleteLink" class="deletelink"><% _t('REMCOM','remove this comment') %></a></li>
|
||||
<% end_if %>
|
||||
</ul>
|
101
tests/CommentsTest.php
Normal file
101
tests/CommentsTest.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package comments
|
||||
*/
|
||||
class CommentsTest extends FunctionalTest {
|
||||
|
||||
static $fixture_file = 'comments/tests/CommentsTest.yml';
|
||||
|
||||
function testCanView() {
|
||||
$visitor = $this->objFromFixture('Member', 'visitor');
|
||||
$admin = $this->objFromFixture('Member', 'commentadmin');
|
||||
$comment = $this->objFromFixture('PageComment', 'firstComA');
|
||||
|
||||
$this->assertTrue($comment->canView($visitor),
|
||||
'Unauthenticated members can view comments associated to a page with ProvideComments=1'
|
||||
);
|
||||
$this->assertTrue($comment->canView($admin),
|
||||
'Admins with CMS_ACCESS_CommentAdmin permissions can view comments associated to a page with ProvideComments=1'
|
||||
);
|
||||
|
||||
$disabledComment = $this->objFromFixture('PageComment', 'disabledCom');
|
||||
|
||||
$this->assertFalse($disabledComment->canView($visitor),
|
||||
'Unauthenticated members can not view comments associated to a page with ProvideComments=0'
|
||||
);
|
||||
$this->assertTrue($disabledComment->canView($admin),
|
||||
'Admins with CMS_ACCESS_CommentAdmin permissions can view comments associated to a page with ProvideComments=0'
|
||||
);
|
||||
}
|
||||
|
||||
function testCanEdit() {
|
||||
$visitor = $this->objFromFixture('Member', 'visitor');
|
||||
$admin = $this->objFromFixture('Member', 'commentadmin');
|
||||
$comment = $this->objFromFixture('PageComment', 'firstComA');
|
||||
|
||||
$this->assertFalse($comment->canEdit($visitor));
|
||||
$this->assertTrue($comment->canEdit($admin));
|
||||
}
|
||||
|
||||
function testCanDelete() {
|
||||
$visitor = $this->objFromFixture('Member', 'visitor');
|
||||
$admin = $this->objFromFixture('Member', 'commentadmin');
|
||||
$comment = $this->objFromFixture('PageComment', 'firstComA');
|
||||
|
||||
$this->assertFalse($comment->canEdit($visitor));
|
||||
$this->assertTrue($comment->canEdit($admin));
|
||||
}
|
||||
|
||||
function testDeleteComment() {
|
||||
$firstPage = $this->objFromFixture('Page', 'first');
|
||||
$this->autoFollowRedirection = false;
|
||||
$this->logInAs('commentadmin');
|
||||
|
||||
$firstComment = $this->objFromFixture('PageComment', 'firstComA');
|
||||
$firstCommentID = $firstComment->ID;
|
||||
Director::test($firstPage->RelativeLink(), null, $this->session());
|
||||
Director::test('PageComment/deletecomment/'.$firstComment->ID, null, $this->session());
|
||||
|
||||
$this->assertFalse(DataObject::get_by_id('PageComment', $firstCommentID));
|
||||
}
|
||||
|
||||
function testDeleteAllCommentsOnPage() {
|
||||
$second = $this->objFromFixture('Page', 'second');
|
||||
$this->autoFollowRedirection = false;
|
||||
$this->logInAs('commentadmin');
|
||||
|
||||
Director::test('second-page', null, $this->session());
|
||||
Director::test('PageComment/deleteallcomments?pageid='.$second->ID,
|
||||
null, $this->session());
|
||||
Director::test('second-page', null, $this->session());
|
||||
|
||||
$secondComments = DataObject::get('PageComment', '"ParentID" = '.$second->ID);
|
||||
$this->assertNull($secondComments);
|
||||
|
||||
$first = $this->objFromFixture('Page', 'first');
|
||||
$firstComments = DataObject::get('PageComment', '"ParentID" = '.$first->ID);
|
||||
$this->assertNotNull($firstComments);
|
||||
|
||||
$third = $this->objFromFixture('Page', 'third');
|
||||
$thirdComments = DataObject::get('PageComment', '"ParentID" = '.$third->ID);
|
||||
$this->assertEquals($thirdComments->Count(), 3);
|
||||
}
|
||||
|
||||
function testCommenterURLWrite() {
|
||||
$comment = new PageComment();
|
||||
// We only care about the CommenterURL, so only set that
|
||||
// Check a http and https URL. Add more test urls here as needed.
|
||||
$protocols = array(
|
||||
'Http',
|
||||
'Https',
|
||||
);
|
||||
$url = '://example.com';
|
||||
foreach($protocols as $protocol) {
|
||||
$comment->CommenterURL = $protocol . $url;
|
||||
// The protocol should stay as if, assuming it is valid
|
||||
$comment->write();
|
||||
$this->assertEquals($comment->CommenterURL, $protocol . $url, $protocol . ':// is a valid protocol');
|
||||
}
|
||||
}
|
||||
}
|
62
tests/CommentsTest.yml
Normal file
62
tests/CommentsTest.yml
Normal file
@ -0,0 +1,62 @@
|
||||
Member:
|
||||
commentadmin:
|
||||
FirstName: admin
|
||||
visitor:
|
||||
FirstName: visitor
|
||||
|
||||
Group:
|
||||
commentadmins:
|
||||
Title: Admin
|
||||
Members: =>Member.commentadmin
|
||||
|
||||
Permission:
|
||||
admin:
|
||||
Code: CMS_ACCESS_CommentAdmin
|
||||
Group: =>Group.commentadmins
|
||||
|
||||
Page:
|
||||
first:
|
||||
Title: First page
|
||||
URLSegment: first-page
|
||||
ProvideComments: 1
|
||||
second:
|
||||
Title: Second page
|
||||
URLSegment: second-page
|
||||
ProvideComments: 1
|
||||
third:
|
||||
Title: Third page
|
||||
URLSegment:third-page
|
||||
ProvideComments: 1
|
||||
pageNoComments:
|
||||
Title: No comments
|
||||
URLSegment: no-comments
|
||||
ProvideComments: 0
|
||||
|
||||
PageComment:
|
||||
firstComA:
|
||||
ParentID: =>Page.first
|
||||
Name: FA
|
||||
Comment: textFA
|
||||
secondComA:
|
||||
ParentID: =>Page.second
|
||||
Name: SA
|
||||
Comment: textSA
|
||||
secondComB:
|
||||
ParentID: =>Page.second
|
||||
Name: SB
|
||||
Comment: textSB
|
||||
thirdComA:
|
||||
ParentID: =>Page.third
|
||||
Name: TA
|
||||
Comment: textTA
|
||||
thirdComB:
|
||||
ParentID: =>Page.third
|
||||
Name: TB
|
||||
Comment: textTB
|
||||
thirdComC:
|
||||
ParentID: =>Page.third
|
||||
Name: TC
|
||||
Comment: textTC
|
||||
disabledCom:
|
||||
ParentID: =>Page.pageNoComments
|
||||
Name: Disabled
|
Loading…
Reference in New Issue
Block a user