diff --git a/_config.php b/_config.php index 13b4766..38c672a 100644 --- a/_config.php +++ b/_config.php @@ -1,3 +1,5 @@ filter('Moderated',0), + $newComments = Comment::get()->filter('Moderated', 0); + + $newGrid = new GridField( + 'NewComments', + _t('CommentsAdmin.NewComments', 'Unmoderated'), + $newComments, $commentsConfig ); - $moderated = new GridField( - 'CommentsModerated', - _t('CommentsAdmin.Moderated', 'Moderated'), - Comment::get()->filter('Moderated',1), + $approvedComments = Comment::get()->filter('Moderated', 1)->filter('IsSpam', 0); + + $approvedGrid = new GridField( + 'ApprovedComments', + _t('CommentsAdmin.ApprovedComments', 'Displayed'), + $approvedComments, $commentsConfig ); + $spamComments = Comment::get()->filter('Moderated', 1)->filter('IsSpam', 1); + + $spamGrid = new GridField( + 'SpamComments', + _t('CommentsAdmin.SpamComments', 'Spam'), + $spamComments, + $commentsConfig + ); + + $newCount = '(' . count($newComments) . ')'; + $approvedCount = '(' . count($approvedComments) . ')'; + $spamCount = '(' . count($spamComments) . ')'; + $fields = new FieldList( $root = new TabSet( 'Root', - new Tab('NeedsModeration', _t('CommentAdmin.NeedsModeration', 'Needs Moderation'), - $needs + new Tab('NewComments', _t('CommentAdmin.NewComments', 'Unmoderated') . ' ' . $newCount, + $newGrid ), - new Tab('Comments', _t('CommentAdmin.Moderated', 'Moderated'), - $moderated + new Tab('ApprovedComments', _t('CommentAdmin.ApprovedComments', 'Displayed') . ' ' . $approvedCount, + $approvedGrid + ), + new Tab('SpamComments', _t('CommentAdmin.SpamComments', 'Spam') . ' ' . $spamCount, + $spamGrid ) ) ); - + $root->setTemplate('CMSTabSet'); $actions = new FieldList(); - + $form = new Form( $this, 'EditForm', @@ -88,7 +108,7 @@ class CommentAdmin extends LeftAndMain implements PermissionProvider { $form->addExtraClass('cms-edit-form'); $form->setTemplate($this->getTemplatesWithSuffix('_EditForm')); - if($form->Fields()->hasTabset()) { + if($form->Fields()->hasTabset()) { $form->Fields()->findOrMakeTab('Root')->setTemplate('CMSTabSet'); $form->addExtraClass('center ss-tabset cms-tabset ' . $this->BaseCSSClasses()); } diff --git a/code/admin/CommentsGridFieldAction.php b/code/admin/CommentsGridFieldAction.php new file mode 100644 index 0000000..6e1c98f --- /dev/null +++ b/code/admin/CommentsGridFieldAction.php @@ -0,0 +1,102 @@ + 'col-buttons'); + } + + /** + * {@inheritdoc} + */ + public function getColumnMetadata($gridField, $columnName) { + if($columnName == 'Actions') { + return array('title' => ''); + } + } + + /** + * {@inheritdoc} + */ + public function getColumnsHandled($gridField) { + return array('Actions'); + } + + /** + * {@inheritdoc} + */ + public function getColumnContent($gridField, $record, $columnName) { + if(!$record->canEdit()) return; + + $field = ""; + + $field .= GridField_FormAction::create( + $gridField, + 'CustomAction' . $record->ID, + 'Mark As Spam', + 'spam', + array('RecordID' => $record->ID) + )->Field(); + + $field .= GridField_FormAction::create( + $gridField, + 'CustomAction' . $record->ID, + 'Mark As Not Spam', + 'not_spam', + array('RecordID' => $record->ID) + )->Field(); + + return $field; + } + + /** + * {@inheritdoc} + */ + public function getActions($gridField) { + return array('spam', 'not_spam'); + } + + /** + * {@inheritdoc} + */ + public function handleAction(GridField $gridField, $actionName, $arguments, $data) { + if($actionName == 'spam') { + $comment = Comment::get()->byID($arguments["RecordID"]); + + $comment->Moderated = true; + $comment->IsSpam = true; + $comment->write(); + + // output a success message to the user + Controller::curr()->getResponse()->setStatusCode( + 200, + 'Comment marked as spam.' + ); + } + + if($actionName == 'not_spam') { + $comment = Comment::get()->byID($arguments["RecordID"]); + + $comment->Moderated = true; + $comment->IsSpam = false; + $comment->write(); + + // output a success message to the user + Controller::curr()->getResponse()->setStatusCode( + 200, + 'Comment marked as not spam.' + ); + } + } +} \ No newline at end of file diff --git a/code/admin/CommentsGridFieldBulkAction.php b/code/admin/CommentsGridFieldBulkAction.php index d7a627c..92ad1b8 100644 --- a/code/admin/CommentsGridFieldBulkAction.php +++ b/code/admin/CommentsGridFieldBulkAction.php @@ -12,14 +12,16 @@ class CommentsGridFieldBulkAction extends GridFieldBulkActionHandler { * * @package comments */ -class CommentsGridFieldBulkAction_MarkAsSpam extends CommentsGridFieldBulkAction { +class CommentsGridFieldBulkAction_Handlers extends CommentsGridFieldBulkAction { private static $allowed_actions = array( - 'markAsSpam' + 'markAsSpam', + 'markAsNotSpam', ); private static $url_handlers = array( - 'markAsSpam' => 'markAsSpam' + 'markAsSpam' => 'markAsSpam', + 'markAsNotSpam' => 'markAsNotSpam', ); @@ -43,4 +45,26 @@ class CommentsGridFieldBulkAction_MarkAsSpam extends CommentsGridFieldBulkAction return $response; } + + + public function markAsNotSpam(SS_HTTPRequest $request) { + $ids = array(); + + foreach($this->getRecords() as $record) { + array_push($ids, $record->ID); + + $record->Moderated = 1; + $record->IsSpam = 0; + $record->write(); + } + + $response = new SS_HTTPResponse(Convert::raw2json(array( + 'done' => true, + 'records' => $ids + ))); + + $response->addHeader('Content-Type', 'text/json'); + + return $response; + } } \ No newline at end of file diff --git a/code/admin/CommentsGridFieldConfig.php b/code/admin/CommentsGridFieldConfig.php index cf848a3..ab7a9e5 100644 --- a/code/admin/CommentsGridFieldConfig.php +++ b/code/admin/CommentsGridFieldConfig.php @@ -4,7 +4,9 @@ class CommentsGridFieldConfig extends GridFieldConfig_RecordEditor { public function __construct($itemsPerPage = 25) { parent::__construct($itemsPerPage); - $this->addComponent(new GridFieldExportButton()); + // $this->addComponent(new GridFieldExportButton()); + + $this->addComponent(new CommentsGridFieldAction()); // Format column $columns = $this->getComponentByType('GridFieldDataColumns'); @@ -20,14 +22,28 @@ class CommentsGridFieldConfig extends GridFieldConfig_RecordEditor { // Add bulk option $manager = new GridFieldBulkManager(); + $manager->addBulkAction( - 'markAsSpam', 'Mark as spam', 'CommentsGridFieldBulkAction_MarkAsSpam', + 'markAsSpam', 'Mark as spam', 'CommentsGridFieldBulkAction_Handlers', array( 'isAjax' => true, - 'icon' => 'delete', - 'isDestructive' => true + 'icon' => 'cross', + 'isDestructive' => false ) ); + + $manager->addBulkAction( + 'markAsNotSpam', 'Mark as not spam', 'CommentsGridFieldBulkAction_Handlers', + array( + 'isAjax' => true, + 'icon' => 'cross', + 'isDestructive' => false + ) + ); + + $manager->removeBulkAction('bulkEdit'); + $manager->removeBulkAction('unLink'); + $this->addComponent($manager); } } \ No newline at end of file diff --git a/code/dataobjects/Comment.php b/code/dataobjects/Comment.php index a8cb12b..32e79bd 100755 --- a/code/dataobjects/Comment.php +++ b/code/dataobjects/Comment.php @@ -3,46 +3,50 @@ /** * Represents a single comment object. * - * @property string $Name - * @property string $Comment - * @property string $Email - * @property string $URL - * @property string $BaseClass + * @property string $Name + * @property string $Comment + * @property string $Email + * @property string $URL + * @property string $BaseClass * @property boolean $Moderated - * @property boolean $IsSpam True if the comment is known as spam - * @property integer $ParentID ID of the parent page / dataobject - * @property boolean $AllowHtml If true, treat $Comment as HTML instead of plain text - * @property string $SecretToken Secret admin token required to provide moderation links between sessions + * @property boolean $IsSpam True if the comment is known as spam + * @property integer $ParentID ID of the parent page / dataobject + * @property boolean $AllowHtml If true, treat $Comment as HTML instead of plain text + * @property string $SecretToken Secret admin token required to provide moderation links between sessions + * * @method HasManyList ChildComments() List of child comments * @method Member Author() Member object who created this comment + * * @package comments */ class Comment extends DataObject { - + /** + * @var array + */ private static $db = array( - "Name" => "Varchar(200)", - "Comment" => "Text", - "Email" => "Varchar(200)", - "URL" => "Varchar(255)", - "BaseClass" => "Varchar(200)", - "Moderated" => "Boolean(1)", - "IsSpam" => "Boolean(0)", - "ParentID" => "Int", - 'AllowHtml' => "Boolean", - "SecretToken" => "Varchar(255)", + 'Name' => 'Varchar(200)', + 'Comment' => 'Text', + 'Email' => 'Varchar(200)', + 'URL' => 'Varchar(255)', + 'BaseClass' => 'Varchar(200)', + 'Moderated' => 'Boolean(0)', + 'IsSpam' => 'Boolean(0)', + 'ParentID' => 'Int', + 'AllowHtml' => 'Boolean', + 'SecretToken' => 'Varchar(255)', ); private static $has_one = array( - "Author" => "Member", + 'Author' => 'Member', ); - + private static $default_sort = '"Created" DESC'; - + private static $defaults = array( - "Moderated" => 1, - "IsSpam" => 0, + 'Moderated' => 0, + 'IsSpam' => 0, ); - + private static $casting = array( 'Title' => 'Varchar', 'ParentTitle' => 'Varchar', @@ -63,13 +67,13 @@ class Comment extends DataObject { 'Created', 'BaseClass', ); - + private static $summary_fields = array( 'Name' => 'Submitted By', 'Email' => 'Email', 'Comment' => 'Comment', 'Created' => 'Date Posted', - 'ParentTitle' => 'Parent', + 'ParentTitle' => 'Post', 'IsSpam' => 'Is Spam', ); @@ -88,47 +92,49 @@ class Comment extends DataObject { public function getSecurityToken() { return Injector::inst()->createWithArgs('Comment_SecurityToken', array($this)); } - + /** * Migrates the old {@link PageComment} objects to {@link Comment} */ public function requireDefaultRecords() { parent::requireDefaultRecords(); - + if(DB::getConn()->hasTable('PageComment')) { - $comments = DB::query("SELECT * FROM \"PageComment\""); - + $comments = DB::query('SELECT * FROM "PageComment"'); + if($comments) { while($pageComment = $comments->nextRecord()) { // create a new comment from the older page comment $comment = new Comment(); $comment->update($pageComment); - + // set the variables which have changed $comment->BaseClass = 'SiteTree'; - $comment->URL = (isset($pageComment['CommenterURL'])) ? $pageComment['CommenterURL'] : ""; - if((int)$pageComment['NeedsModeration'] == 0) $comment->Moderated = true; - + $comment->URL = (isset($pageComment['CommenterURL'])) ? $pageComment['CommenterURL'] : ''; + if((int) $pageComment['NeedsModeration'] == 0) $comment->Moderated = true; + $comment->write(); } } - - DB::alteration_message("Migrated PageComment to Comment","changed"); + + DB::alteration_message('Migrated PageComment to Comment', 'changed'); DB::getConn()->dontRequireTable('PageComment'); } } - + /** * Return a link to this comment * + * @param string $action + * * @return string link to this comment. */ - public function Link($action = "") { - if($parent = $this->getParent()){ + public function Link($action = '') { + if($parent = $this->getParent()) { return $parent->Link($action) . '#' . $this->Permalink(); } } - + /** * Returns the permalink for this {@link Comment}. Inserted into * the ID tag of the comment @@ -139,14 +145,17 @@ class Comment extends DataObject { $prefix = $this->getOption('comment_permalink_prefix'); return $prefix . $this->ID; } - + /** * Translate the form field labels for the CMS administration * * @param boolean $includerelations + * + * @return array */ public function fieldLabels($includerelations = true) { $labels = parent::fieldLabels($includerelations); + $labels['Name'] = _t('Comment.NAME', 'Author Name'); $labels['Comment'] = _t('Comment.COMMENT', 'Comment'); $labels['Email'] = _t('Comment.EMAIL', 'Email'); @@ -155,7 +164,7 @@ class Comment extends DataObject { $labels['Moderated'] = _t('Comment.MODERATED', 'Moderated?'); $labels['ParentTitle'] = _t('Comment.PARENTTITLE', 'Parent'); $labels['Created'] = _t('Comment.CREATED', 'Date posted'); - + return $labels; } @@ -163,6 +172,7 @@ class Comment extends DataObject { * Get the commenting option * * @param string $key + * * @return mixed Result if the setting is available, or null otherwise */ public function getOption($key) { @@ -178,7 +188,7 @@ class Comment extends DataObject { return $record->getCommentsOption($key); } - + /** * Returns the parent {@link DataObject} this comment is attached too * @@ -198,7 +208,7 @@ class Comment extends DataObject { */ public function getParentTitle() { if($parent = $this->getParent()) { - return $parent->Title ?: ($parent->ClassName . " #" . $parent->ID); + return $parent->Title ?: ($parent->ClassName . ' #' . $parent->ID); } } @@ -218,7 +228,7 @@ class Comment extends DataObject { } return parent::castingHelper($field); } - + /** * Content to be safely escaped on the frontend * @@ -240,22 +250,25 @@ class Comment extends DataObject { /** * @todo needs to compare to the new {@link Commenting} configuration API * - * @return Boolean + * @param Member $member + * + * @return bool */ public function canCreate($member = null) { return false; } /** - * Checks for association with a page, and {@link SiteTree->ProvidePermission} + * Checks for association with a page, and {@link SiteTree->ProvidePermission} * flag being set to true. - * + * * @param Member $member + * * @return Boolean */ public 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; @@ -267,40 +280,42 @@ class Comment extends DataObject { $parent = $this->getParent(); return $parent && $parent->ProvideComments && $parent->canView($member); } - + /** - * Checks for "CMS_ACCESS_CommentAdmin" permission codes and - * {@link canView()}. - * + * Checks for "CMS_ACCESS_CommentAdmin" permission codes and + * {@link canView()}. + * * @param Member $member + * * @return Boolean */ public 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'); + + return (bool) Permission::checkMember($member, 'CMS_ACCESS_CommentAdmin'); } - + /** - * Checks for "CMS_ACCESS_CommentAdmin" permission codes and + * Checks for "CMS_ACCESS_CommentAdmin" permission codes and * {@link canEdit()}. - * + * * @param Member $member + * * @return Boolean */ public 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); } @@ -322,6 +337,7 @@ class Comment extends DataObject { * * @param string $action An action on CommentingController to link to * @param Member $member The member authorised to invoke this action + * * @return string */ protected function actionLink($action, $member = null) { @@ -330,7 +346,7 @@ class Comment extends DataObject { $url = Controller::join_links( Director::baseURL(), - "CommentingController", + 'CommentingController', $action, $this->ID ); @@ -344,6 +360,7 @@ class Comment extends DataObject { * Link to delete this comment * * @param Member $member + * * @return string */ public function DeleteLink($member = null) { @@ -351,11 +368,12 @@ class Comment extends DataObject { return $this->actionLink('delete', $member); } } - + /** * Link to mark as spam * * @param Member $member + * * @return string */ public function SpamLink($member = null) { @@ -363,11 +381,12 @@ class Comment extends DataObject { return $this->actionLink('spam', $member); } } - + /** * Link to mark as not-spam (ham) * * @param Member $member + * * @return string */ public function HamLink($member = null) { @@ -375,11 +394,12 @@ class Comment extends DataObject { return $this->actionLink('ham', $member); } } - + /** * Link to approve this comment * * @param Member $member + * * @return string */ public function ApproveLink($member = null) { @@ -387,7 +407,7 @@ class Comment extends DataObject { return $this->actionLink('approve', $member); } } - + /** * @return string */ @@ -400,16 +420,16 @@ class Comment extends DataObject { return 'notspam'; } } - + /** * @return string */ public function getTitle() { - $title = sprintf(_t('Comment.COMMENTBY', "Comment by %s", 'Name'), $this->getAuthorName()); + $title = sprintf(_t('Comment.COMMENTBY', 'Comment by %s', 'Name'), $this->getAuthorName()); if($parent = $this->getParent()) { if($parent->Title) { - $title .= sprintf(" %s %s", _t('Comment.ON', 'on'), $parent->Title); + $title .= sprintf(' %s %s', _t('Comment.ON', 'on'), $parent->Title); } } @@ -433,6 +453,7 @@ class Comment extends DataObject { /** * @param String $dirtyHtml + * * @return String */ public function purifyHtml($dirtyHtml) { @@ -454,19 +475,19 @@ class Comment extends DataObject { } /** - * Calcualate the gravatar link from the email address + * Calculate the Gravatar link from the email address * * @return string */ public function Gravatar() { $gravatar = ''; $use_gravatar = $this->getOption('use_gravatar'); - if ($use_gravatar) { - $gravatar = "http://www.gravatar.com/avatar/" . md5( strtolower(trim($this->Email))); + if($use_gravatar) { + $gravatar = 'http://www.gravatar.com/avatar/' . md5(strtolower(trim($this->Email))); $gravatarsize = $this->getOption('gravatar_size'); $gravatardefault = $this->getOption('gravatar_default'); $gravatarrating = $this->getOption('gravatar_rating'); - $gravatar.= "?s=".$gravatarsize."&d=".$gravatardefault."&r=".$gravatarrating; + $gravatar .= '?s=' . $gravatarsize . '&d=' . $gravatardefault . '&r=' . $gravatarrating; } return $gravatar; @@ -495,6 +516,7 @@ class Comment_SecurityToken { * Generate the token for the given salt and current secret * * @param string $salt + * * @return string */ protected function getToken($salt) { @@ -506,11 +528,13 @@ class Comment_SecurityToken { /** * Get the member-specific salt. * - * The reason for making the salt specific to a user is that it cannot be "passed in" via a querystring, - * requiring the same user to be present at both the link generation and the controller action. + * The reason for making the salt specific to a user is that it cannot be "passed in" via a + * querystring, requiring the same user to be present at both the link generation and the + * controller action. + * + * @param string $salt Single use salt + * @param Member $member Member object * - * @param string $salt Single use salt - * @param type $member Member object * @return string Generated salt specific to this member */ protected function memberSalt($salt, $member) { @@ -519,8 +543,9 @@ class Comment_SecurityToken { } /** - * @param string $url Comment action URL + * @param string $url Comment action URL * @param Member $member Member to restrict access to this action to + * * @return string */ public function addToUrl($url, $member) { @@ -540,6 +565,7 @@ class Comment_SecurityToken { /** * @param SS_HTTPRequest $request + * * @return boolean */ public function checkRequest($request) { @@ -559,12 +585,13 @@ class Comment_SecurityToken { * Generates new random key * * @param integer $length + * * @return string */ protected function generate($length = null) { $generator = new RandomGenerator(); $result = $generator->randomToken('sha256'); - if($length !== null) return substr ($result, 0, $length); + if($length !== null) return substr($result, 0, $length); return $result; } @@ -580,24 +607,24 @@ class Comment_SecurityToken { * * @return string derived key */ - private function hash_pbkdf2 ($a, $p, $s, $c, $kl, $st=0) { + private function hash_pbkdf2($a, $p, $s, $c, $kl, $st = 0) { - $kb = $st+$kl; // Key blocks to compute - $dk = ''; // Derived key + $kb = $st + $kl; // Key blocks to compute + $dk = ''; // Derived key // Create key - for ($block=1; $block<=$kb; $block++) { + for($block = 1; $block <= $kb; $block++) { // Initial hash for this block $ib = $h = hash_hmac($a, $s . pack('N', $block), $p, true); // Perform block iterations - for ($i=1; $i<$c; $i++) { + for($i = 1; $i < $c; $i++) { // XOR each iterate - $ib ^= ($h = hash_hmac($a, $h, $p, true)); + $ib ^= ($h = hash_hmac($a, $h, $p, true)); } - $dk .= $ib; // Append iterated block + $dk .= $ib; // Append iterated block } diff --git a/code/extensions/CommentsExtension.php b/code/extensions/CommentsExtension.php index 375f7ce..08e9bf0 100644 --- a/code/extensions/CommentsExtension.php +++ b/code/extensions/CommentsExtension.php @@ -5,47 +5,61 @@ * * @package comments */ - class CommentsExtension extends DataExtension { - /** * Default configuration values - * - * @var array + * + * enabled: Allows commenting to be disabled even if the extension is present + * enabled_cms: Allows commenting to be enabled or disabled via the CMS + * require_login: Boolean, whether a user needs to login (required for required_permission) + * require_login_cms: Allows require_login to be set via the CMS + * required_permission: Permission (or array of permissions) required to comment + * include_js: Enhance operation by ajax behaviour on moderation links (required for use_preview) + * use_gravatar: Set to true to show gravatar icons + * gravatar_default: Theme for 'not found' gravatar {@see http://gravatar.com/site/implement/images} + * gravatar_rating: Gravatar rating (same as the standard default) + * show_comments_when_disabled: Show older comments when commenting has been disabled. + * comments_holder_id: ID for the comments holder + * comment_permalink_prefix: ID prefix for each comment + * require_moderation: Require moderation for all comments + * require_moderation_cms: Ignore other comment moderation config settings and set via CMS + * html_allowed: Allow for sanitized HTML in comments + * use_preview: Preview formatted comment (when allowing HTML) + * + * @var array + * * @config */ private static $comments = array( - 'enabled' => true, // Allows commenting to be disabled even if the extension is present - 'enabled_cms' => false, // Allows commenting to be enabled or disabled via the CMS - 'require_login' => false, // boolean, whether a user needs to login - 'require_login_cms' => false, // Allows require_login to be set via the CMS - // required permission to comment (or array of permissions). require_login must be set for this to work + 'enabled' => true, + 'enabled_cms' => false, + 'require_login' => false, + 'require_login_cms' => false, 'required_permission' => false, - 'include_js' => true, // Enhance operation by ajax behaviour on moderation links - 'use_gravatar' => false, // set to true to show gravatar icons, - 'gravatar_size' => 80, // size of gravatar in pixels. This is the same as the standard default - // theme for 'not found' gravatar (see http://gravatar.com/site/implement/images/) + 'include_js' => true, + 'use_gravatar' => false, + 'gravatar_size' => 80, 'gravatar_default' => 'identicon', - 'gravatar_rating' => 'g', // gravatar rating. This is the same as the standard default - // when comments are disabled should we show older comments (if available) + 'gravatar_rating' => 'g', 'show_comments_when_disabled' => false, - 'order_comments_by' => "\"Created\" DESC", + 'order_comments_by' => '"Created" DESC', '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, // Require moderation for all comments - // requires moderation for comments posted by non-members. 'require_moderation' overrides this if set. + 'comments_holder_id' => 'comments-holder', + 'comment_permalink_prefix' => 'comment-', + 'require_moderation' => false, 'require_moderation_nonmembers' => false, - // If true, ignore above values and configure moderation requirements via the CMS only 'require_moderation_cms' => false, - 'html_allowed' => false, // allow for sanitized HTML in comments + 'html_allowed' => false, 'html_allowed_elements' => array('a', 'img', 'i', 'b'), - 'use_preview' => false, // preview formatted comment (when allowing HTML). Requires include_js=true + 'use_preview' => false, ); + /** + * @var array + */ private static $db = array( 'ProvideComments' => 'Boolean', - 'ModerationRequired' => "Enum('None,Required,NonMembersOnly','None')", + 'ModerationRequired' => 'Enum(\'None,Required,NonMembersOnly\',\'None\')', 'CommentsRequireLogin' => 'Boolean', ); @@ -56,7 +70,7 @@ class CommentsExtension extends DataExtension { // Set if comments should be enabled by default $this->owner->ProvideComments = $this->owner->getCommentsOption('enabled') ? 1 : 0; - // If moderations options should be configurable via the CMS then + // If moderation options should be configurable via the CMS then if($this->owner->getCommentsOption('require_moderation')) { $this->owner->ModerationRequired = 'Required'; } elseif($this->owner->getCommentsOption('require_moderation_nonmembers')) { @@ -68,7 +82,7 @@ class CommentsExtension extends DataExtension { $this->owner->CommentsRequireLogin = $this->owner->getCommentsOption('require_login') ? 1 : 0; } - + /** * If this extension is applied to a {@link SiteTree} record then * append a Provide Comments checkbox to allow authors to trigger @@ -76,12 +90,12 @@ class CommentsExtension extends DataExtension { * * @todo Allow customization of other {@link Commenting} configuration * - * @param FieldSet + * @param FieldList $fields */ public function updateSettingsFields(FieldList $fields) { $options = FieldGroup::create()->setTitle(_t('CommentsExtension.COMMENTOPTIONS', 'Comments')); - + // Check if enabled setting should be cms configurable if($this->owner->getCommentsOption('enabled_cms')) { $options->push(new CheckboxField('ProvideComments', _t('Comment.ALLOWCOMMENTS', 'Allow Comments'))); @@ -136,15 +150,19 @@ class CommentsExtension extends DataExtension { } public function getComments() { - Deprecation::notice('2.0', 'Use PagedComments to get paged coments'); + // TODO: find out why this is being triggered when combined with blog + // Deprecation::notice('2.0', 'Use PagedComments to get paged comments'); return $this->PagedComments(); } /** * Get comment moderation rules for this parent * - * @return string A value of either 'None' (no moderation required), 'Required' (all comments), - * or 'NonMembersOnly' (only not logged in users) + * None: No moderation required + * Required: All comments + * NonMembersOnly: Only anonymous users + * + * @return string */ public function getModerationRequired() { if($this->owner->getCommentsOption('require_moderation_cms')) { @@ -165,9 +183,9 @@ class CommentsExtension extends DataExtension { */ public function getCommentsRequireLogin() { if($this->owner->getCommentsOption('require_login_cms')) { - return (bool)$this->owner->getField('CommentsRequireLogin'); + return (bool) $this->owner->getField('CommentsRequireLogin'); } else { - return (bool)$this->owner->getCommentsOption('require_login'); + return (bool) $this->owner->getCommentsOption('require_login'); } } @@ -183,10 +201,10 @@ class CommentsExtension extends DataExtension { ->AllComments() ->sort($order) ->filter('IsSpam', 0); - - // Filter unmoderated comments for non-administrators if moderation is enabled - if ($this->owner->ModerationRequired !== 'None') { - $list = $list->filter('Moderated', 1); + + // Filter un-moderated comments for non-administrators if moderation is enabled + if($this->owner->ModerationRequired !== 'None') { + $list = $list->filter('Moderated', 1); } $this->owner->extend('updateComments', $list); @@ -201,10 +219,10 @@ class CommentsExtension extends DataExtension { */ public function PagedComments() { $list = $this->Comments(); - + // Add pagination $list = new PaginatedList($list, Controller::curr()->getRequest()); - $list->setPaginationGetVar('commentsstart'.$this->owner->ID); + $list->setPaginationGetVar('commentsstart' . $this->owner->ID); $list->setPageLength($this->owner->getCommentsOption('comments_per_page')); $this->owner->extend('updatePagedComments', $list); @@ -276,6 +294,7 @@ class CommentsExtension extends DataExtension { * Determine if a user can post comments on this item * * @param Member $member Member to check + * * @return boolean */ public function canPostComment($member = null) { @@ -301,6 +320,7 @@ class CommentsExtension extends DataExtension { * Determine if this member can moderate comments in the CMS * * @param Member $member + * * @return boolean */ public function canModerateComments($member = null) { @@ -318,7 +338,7 @@ class CommentsExtension extends DataExtension { * @return string */ public function getCommentRSSLink() { - return Controller::join_links(Director::baseURL(), "CommentingController/rss"); + return Controller::join_links(Director::baseURL(), 'CommentingController/rss'); } public function getRssLinkPage() { @@ -336,17 +356,17 @@ class CommentsExtension extends DataExtension { $this->getCommentRSSLink(), $this->ownerBaseClass, $this->owner->ID ); } - + /** * Comments interface for the front end. Includes the CommentAddForm and the composition - * of the comments display. - * + * of the comments display. + * * To customize the html see templates/CommentInterface.ss or extend this function with * your own extension. * * @todo Cleanup the passing of all this configuration based functionality * - * @see docs/en/Extending + * @see docs/en/Extending */ public function CommentsForm() { // Check if enabled @@ -357,7 +377,7 @@ class CommentsExtension extends DataExtension { Requirements::javascript(THIRDPARTY_DIR . '/jquery-validate/jquery.validate.pack.js'); Requirements::javascript('comments/javascript/CommentsInterface.js'); } - + $controller = CommentingController::create(); $controller->setOwnerRecord($this->owner); $controller->setBaseClass($this->ownerBaseClass); @@ -378,7 +398,7 @@ class CommentsExtension extends DataExtension { )) ->renderWith('CommentsInterface'); } - + /** * Returns whether this extension instance is attached to a {@link SiteTree} object * @@ -386,7 +406,7 @@ class CommentsExtension extends DataExtension { */ public function attachedToSiteTree() { $class = $this->ownerBaseClass; - + return (is_subclass_of($class, 'SiteTree')) || ($class == 'SiteTree'); } @@ -405,6 +425,7 @@ class CommentsExtension extends DataExtension { * This can be overridden in any instance or extension to customise the option available * * @param string $key + * * @return mixed Result if the setting is available, or null otherwise */ public function getCommentsOption($key) { @@ -425,41 +446,61 @@ class CommentsExtension extends DataExtension { * @param FieldList $fields */ protected function updateModerationFields(FieldList $fields) { - // Create gridfield config $commentsConfig = CommentsGridFieldConfig::create(); - $needs = new GridField( - 'CommentsNeedsModeration', - _t('CommentsAdmin.NeedsModeration', 'Needs Moderation'), - $this->owner->AllComments()->filter('Moderated', 0), + $newComments = $this->owner->AllComments()->filter('Moderated', 0); + + $newGrid = new GridField( + 'NewComments', + _t('CommentsAdmin.NewComments', 'Unmoderated'), + $newComments, $commentsConfig ); - $moderated = new GridField( - 'CommentsModerated', - _t('CommentsAdmin.Moderated', 'Moderated'), - $this->owner->AllComments()->filter('Moderated', 1), + $approvedComments = $this->owner->AllComments()->filter('Moderated', 1)->filter('IsSpam', 0); + + $approvedGrid = new GridField( + 'ApprovedComments', + _t('CommentsAdmin.Comments', 'Displayed'), + $approvedComments, $commentsConfig ); + $spamComments = $this->owner->AllComments()->filter('Moderated', 1)->filter('IsSpam', 1); + + $spamGrid = new GridField( + 'SpamComments', + _t('CommentsAdmin.SpamComments', 'Spam'), + $spamComments, + $commentsConfig + ); + + $newCount = '(' . count($newComments) . ')'; + $approvedCount = '(' . count($approvedComments) . ')'; + $spamCount = '(' . count($spamComments) . ')'; + if($fields->hasTabSet()) { - $tabset = new TabSet( + $tabs = new TabSet( 'Comments', - new Tab('CommentsNeedsModerationTab', _t('CommentAdmin.NeedsModeration', 'Needs Moderation'), - $needs + new Tab('CommentsNewCommentsTab', _t('CommentAdmin.NewComments', 'Unmoderated') . ' ' . $newCount, + $newGrid ), - new Tab('CommentsModeratedTab', _t('CommentAdmin.Moderated', 'Moderated'), - $moderated + new Tab('CommentsCommentsTab', _t('CommentAdmin.Comments', 'Displayed') . ' ' . $approvedCount, + $approvedGrid + ), + new Tab('CommentsSpamCommentsTab', _t('CommentAdmin.SpamComments', 'Spam') . ' ' . $spamCount, + $spamGrid ) ); - $fields->addFieldToTab('Root', $tabset); + $fields->addFieldToTab('Root', $tabs); } else { - $fields->push($needs); - $fields->push($moderated); + $fields->push($newGrid); + $fields->push($approvedGrid); + $fields->push($spamGrid); } } - public function updateCMSFields(\FieldList $fields) { + public function updateCMSFields(FieldList $fields) { // Disable moderation if not permitted if($this->owner->canModerateComments()) { $this->updateModerationFields($fields); diff --git a/templates/CommentsInterface.ss b/templates/CommentsInterface.ss index 921a659..4577746 100755 --- a/templates/CommentsInterface.ss +++ b/templates/CommentsInterface.ss @@ -20,20 +20,20 @@

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

- <% if $Comments %> + <% if $PagedComments %> - <% with $Comments %> + <% with $PagedComments %> <% include CommentPagination %> <% end_with %> <% end_if %> -

style='display: none' <% end_if %> ><% _t('CommentsInterface_ss.NOCOMMENTSYET','No one has commented on this page yet.') %>

+

style='display: none' <% end_if %> ><% _t('CommentsInterface_ss.NOCOMMENTSYET','No one has commented on this page yet.') %>