Merge pull request #195 from robbieaverill/feature/ss4-compat

SilverStripe 4 compatibility
This commit is contained in:
Damian Mooyman 2017-01-25 17:52:20 +13:00 committed by GitHub
commit 19224d9813
42 changed files with 1300 additions and 1503 deletions

View File

@ -8,18 +8,17 @@ addons:
- tidy
php:
- 5.3
- 5.4
- 5.5
- 5.6
- 7.0
- 7.1
before_install:
- pip install --user codecov
env:
global:
- DB=MYSQL CORE_RELEASE=3.1
- DB=MYSQL CORE_RELEASE=master
- MODULE_PATH=comments
# Set to 1 in the matrix to enable code coverage
@ -29,22 +28,22 @@ matrix:
include:
- php: 5.6
#CommentsListTest breaks with this env: DB=MYSQL CORE_RELEASE=3.2 COVERAGE=1
env: DB=SQLITE CORE_RELEASE=3.2 COVERAGE=1
env: DB=SQLITE CORE_RELEASE=master COVERAGE=1
- php: 5.6
env: DB=MYSQL CORE_RELEASE=3
- php: 5.6
env: DB=MYSQL CORE_RELEASE=3.1
- php: 5.6
env: DB=PGSQL CORE_RELEASE=3.2
allow_failures:
env: DB=MYSQL CORE_RELEASE=master
- php: 7.0
env: DB=MYSQL CORE_RELEASE=master
- php: 7.1
env: DB=MYSQL CORE_RELEASE=master
- php: 5.6
env: DB=PGSQL CORE_RELEASE=master
before_script:
- phpenv rehash
- composer self-update || true
- git clone git://github.com/silverstripe-labs/silverstripe-travis-support.git ~/travis-support
# Install suggested modules in order to maximize test coverage
- php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss --require "ezyang/htmlpurifier:4.*,silverstripe/cms:~3.1"
- php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss --require "ezyang/htmlpurifier:4.*,silverstripe/cms:^4.0@dev"
- cd ~/builds/ss
script:

25
.upgrade.yml Normal file
View File

@ -0,0 +1,25 @@
mappings:
CommentAdmin: SilverStripe\Comments\Admin\CommentAdmin
CommentsGridField: SilverStripe\Comments\Admin\CommentsGridField
CommentsGridFieldAction: SilverStripe\Comments\Admin\CommentsGridFieldAction
CommentsGridFieldBulkAction_Handlers: SilverStripe\Comments\Admin\CommentsGridFieldBulkAction\Handlers
CommentsGridFieldConfig: SilverStripe\Comments\Admin\CommentsGridFieldConfig
CommentingController: SilverStripe\Comments\Controllers\CommentingController
CommentsExtension: SilverStripe\Comments\Extensions\CommentsExtension
Comment: SilverStripe\Comments\Model\Comment
Comment_SecurityToken: SilverStripe\Comments\Model\Comment\SecurityToken
CommentAdminTest: SilverStripe\Comments\Tests\CommentAdminTest
CommentingControllerTest: SilverStripe\Comments\Tests\CommentingControllerTest
CommentingTest: SilverStripe\Comments\Tests\CommentingTest
CommentListTest: SilverStripe\Comments\Tests\CommentListTest
CommentsExtensionTest: SilverStripe\Comments\Tests\CommentsExtensionTest
CommentsGridFieldActionTest: SilverStripe\Comments\Tests\CommentsGridFieldActionTest
CommentsGridFieldBulkActionTest: SilverStripe\Comments\Tests\CommentsGridFieldBulkActionTest
CommentsGridFieldConfigTest: SilverStripe\Comments\Tests\CommentsGridFieldConfigTest
CommentsGridFieldTest: SilverStripe\Comments\Tests\CommentsGridFieldTest
CommentsTest: SilverStripe\Comments\Tests\CommentsTest
CommentableItem: SilverStripe\Comments\Tests\Stubs\CommentableItem
CommentableItemEnabled: SilverStripe\Comments\Tests\Stubs\CommentableItemEnabled
CommentableItemDisabled: SilverStripe\Comments\Tests\Stubs\CommentableItemDisabled
CommentableItem_Controller: SilverStripe\Comments\Tests\Stubs\CommentableItemController
CommentTestHelper: SilverStripe\Comments\Tests\CommentTestHelper

View File

@ -36,7 +36,7 @@ inside the docs folder.
## Requirements
* SilverStripe 3.1
* SilverStripe ^4.0
## Installation

View File

@ -1,6 +1,6 @@
<?php
Deprecation::notification_version('2.0', 'comments');
\SilverStripe\Dev\Deprecation::notification_version('3.0', 'comments');
define('COMMENTS_DIR', basename(__DIR__));
define('COMMENTS_THIRDPARTY', COMMENTS_DIR . DIRECTORY_SEPARATOR . 'thirdparty');

View File

@ -4,6 +4,6 @@ Name: commentssitetree
only:
moduleexists: 'cms'
---
SiteTree:
SilverStripe\CMS\Model\SiteTree:
comments:
enabled_cms: true

View File

@ -2,9 +2,6 @@
Name: commentroutes
After: framework/routes#coreroutes
---
Director:
SilverStripe\Control\Director:
rules:
# handle old 2.4 style urls
'CommentingController//$Action/$ID/$OtherID': 'CommentingController'
'PageComments/$Action/$ID/$OtherID': 'CommentingController'
'PageComments_Controller/$Action/$ID/$OtherID': 'CommentingController'
comments: SilverStripe\Comments\Controllers\CommentingController

View File

@ -1,162 +0,0 @@
<?php
/**
* Helper Class for storing the configuration options. Retains the mapping between
* objects which have comments attached and the related configuration options.
*
* Also handles adding the Commenting extension to the {@link DataObject} on behalf
* of the user.
*
* For documentation on how to use this class see docs/en/Configuration.md
*
* @deprecated since version 2.0
*
* @package comments
*/
class Commenting
{
/**
* Adds commenting to a {@link DataObject}
*
* @deprecated since version 2.0
*
* @param string classname to add commenting to
* @param array $settings Settings. See {@link self::$default_config} for
* available settings
*
* @throws InvalidArgumentException
*/
public static function add($class, $settings = false)
{
Deprecation::notice('2.0', 'Using Commenting::add is deprecated. Please use the config API instead');
Config::inst()->update($class, 'extensions', array('CommentsExtension'));
// Check if settings must be customised
if ($settings === false) {
return;
}
if (!is_array($settings)) {
throw new InvalidArgumentException('$settings needs to be an array or null');
}
Config::inst()->update($class, 'comments', $settings);
}
/**
* Removes commenting from a {@link DataObject}. Does not remove existing comments
* but does remove the extension.
*
* @deprecated since version 2.0
*
* @param string $class Class to remove {@link CommentsExtension} from
*/
public static function remove($class)
{
Deprecation::notice('2.0', 'Using Commenting::remove is deprecated. Please use the config API instead');
$class::remove_extension('CommentsExtension');
}
/**
* Returns whether a given class name has commenting enabled
*
* @deprecated since version 2.0
*
* @return bool
*/
public static function has_commenting($class)
{
Deprecation::notice('2.0', 'Using Commenting::has_commenting is deprecated. Please use the config API instead');
return $class::has_extension('CommentsExtension');
}
/**
* Sets a value for a class of a given config setting. Passing 'all' as the class
* sets it for everything
*
* @deprecated since version 2.0
*
* @param string $class Class to set the value on. Passing 'all' will set it to all
* active mappings
* @param string $key setting to change
* @param mixed $value value of the setting
*/
public static function set_config_value($class, $key, $value = false)
{
Deprecation::notice('2.0', 'Commenting::set_config_value is deprecated. Use the config api instead');
if ($class === "all") {
$class = 'CommentsExtension';
}
Config::inst()->update($class, 'comments', array($key => $value));
}
/**
* Returns a given config value for a commenting class
*
* @deprecated since version 2.0
*
* @param string $class
* @param string $key config value to return
*
* @throws Exception
* @return mixed
*/
public static function get_config_value($class, $key)
{
Deprecation::notice(
'2.0',
'Using Commenting::get_config_value is deprecated. Please use $parent->getCommentsOption() or '
. 'CommentingController::getOption() instead'
);
// Get settings
if (!$class) {
$class = 'CommentsExtension';
} elseif (!$class::has_extension('CommentsExtension')) {
throw new InvalidArgumentException("$class does not have commenting enabled");
}
return singleton($class)->getCommentsOption($key);
}
/**
* Determines whether a config value on the commenting extension
* matches a given value.
*
* @deprecated since version 2.0
*
* @param string $class
* @param string $key
* @param string $value Expected value
* @return boolean
*/
public static function config_value_equals($class, $key, $value)
{
$check = self::get_config_value($class, $key);
if ($check && ($check == $value)) {
return true;
}
}
/**
* Return whether a user can post on a given commenting instance
*
* @deprecated since version 2.0
*
* @param string $class
* @return boolean true
*/
public static function can_member_post($class)
{
Deprecation::notice('2.0', 'Use $instance->canPostComment() directly instead');
$member = Member::currentUser();
// Check permission
$permission = self::get_config_value($class, 'required_permission');
if ($permission && !Permission::check($permission)) {
return false;
}
// Check login required
$requireLogin = self::get_config_value($class, 'require_login');
return !$requireLogin || $member;
}
}

View File

@ -1,98 +0,0 @@
<?php
/**
* Handles polymorphic relation for commentlist
*
* Uses elements of PolymorphicHasManyList in 3.2
*
* @author dmooyman
*/
class CommentList extends HasManyList
{
/**
* Retrieve the name of the class this relation is filtered by
*
* @return string
*/
public function getForeignClass()
{
return $this->dataQuery->getQueryParam('Foreign.Class');
}
public function __construct($parentClassName)
{
parent::__construct('Comment', 'ParentID');
// Ensure underlying DataQuery globally references the class filter
$this->dataQuery->setQueryParam('Foreign.Class', $parentClassName);
// For queries with multiple foreign IDs (such as that generated by
// DataList::relation) the filter must be generalised to filter by subclasses
$classNames = Convert::raw2sql(ClassInfo::subclassesFor($parentClassName));
$this->dataQuery->where(sprintf(
"\"BaseClass\" IN ('%s')", implode("', '", $classNames)
));
}
/**
* Adds the item to this relation.
*
* @param Comment $item The comment to be added
*/
public function add($item)
{
// Check item given
if (is_numeric($item)) {
$item = Comment::get()->byID($item);
}
if (!($item instanceof Comment)) {
throw new InvalidArgumentException("CommentList::add() expecting a Comment object, or ID value");
}
// Validate foreignID
$foreignID = $this->getForeignID();
if (!$foreignID || is_array($foreignID)) {
throw new InvalidArgumentException("CommentList::add() can't be called until a single foreign ID is set");
}
$item->ParentID = $foreignID;
$item->BaseClass = $this->getForeignClass();
$item->write();
}
/**
* Remove a Comment from this relation by clearing the foreign key. Does not actually delete the comment.
*
* @param Comment $item The Comment to be removed
*/
public function remove($item)
{
// Check item given
if (is_numeric($item)) {
$item = Comment::get()->byID($item);
}
if (!($item instanceof Comment)) {
throw new InvalidArgumentException("CommentList::remove() expecting a Comment object, or ID",
E_USER_ERROR);
}
// Don't remove item with unrelated class key
$foreignClass = $this->getForeignClass();
$classNames = ClassInfo::subclassesFor($foreignClass);
if (!in_array($item->BaseClass, $classNames)) {
return;
}
// Don't remove item which doesn't belong to this list
$foreignID = $this->getForeignID();
if (empty($foreignID)
|| (is_array($foreignID) && in_array($item->ParentID, $foreignID))
|| $foreignID == $item->ParentID
) {
$item->ParentID = null;
$item->BaseClass = null;
$item->write();
}
}
}

View File

@ -1,28 +1,33 @@
{
"name": "silverstripe/comments",
"description": "This module provides commenting functionality for Pages and other DataObjects on your SilverStripe site.",
"type": "silverstripe-module",
"keywords": ["silverstripe", "comments"],
"authors": [{
"name": "Will Rossiter",
"email": "will@fullscreen.io"
}],
"require": {
"assertchris/hash-compat": "~1.0",
"silverstripe/framework": "~3.1",
"colymba/gridfield-bulk-editing-tools": "~2.1"
},
"suggest": {
"ezyang/htmlpurifier": "Standards compliant HTML filter written in PHP",
"silverstripe/cms": "The SilverStripe Content Management System"
},
"require-dev": {
"phpunit/PHPUnit": "~3.7@stable"
},
"extra": {
"branch-alias": {
"dev-master": "2.1.x-dev"
}
},
"license": "BSD-3-Clause"
"name": "silverstripe/comments",
"description": "This module provides commenting functionality for Pages and other DataObjects on your SilverStripe site.",
"type": "silverstripe-module",
"keywords": ["silverstripe", "comments"],
"authors": [{
"name": "Will Rossiter",
"email": "will@fullscreen.io"
}],
"require": {
"silverstripe/framework": "^4.0@dev",
"colymba/gridfield-bulk-editing-tools": "~2.1"
},
"suggest": {
"ezyang/htmlpurifier": "Standards compliant HTML filter written in PHP",
"silverstripe/cms": "The SilverStripe Content Management System"
},
"require-dev": {
"phpunit/PHPUnit": "~4.8"
},
"extra": {
"branch-alias": {
"dev-master": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"SilverStripe\\Comments\\": "src/",
"SilverStripe\\Comments\\Tests\\": "tests/"
}
},
"license": "BSD-3-Clause"
}

View File

@ -2,16 +2,16 @@
## Overview
The module provides a number of built in configuration settings below are the
The module provides a number of built in configuration settings below are the
default settings
In order to add commenting to your site, the minimum amount of work necessary is to add the `CommentsExtension` to
the base class for the object which holds comments.
```yaml
SiteTree:
SilverStripe\CMS\Model\SiteTree:
extensions:
- CommentsExtension
- SilverStripe\Comments\Extensions\CommentsExtension
```
## Configuration
@ -20,9 +20,9 @@ In order to configure options for any class you should assign the specific optio
config of the specified class.
```yaml
SiteTree:
SilverStripe\CMS\Model\SiteTree:
extensions:
- CommentsExtension
- SilverStripe\Comments\Extensions\CommentsExtension
comments:
enabled: true # Enables commenting to be disabled for a specific class (or subclass of a parent with commenting enabled)
enabled_cms: false # The 'enabled' option will be set via the CMS instead of config
@ -58,12 +58,12 @@ SiteTree:
Enabling any of the *_cms options will instead allow these options to be configured under the settings tab
of each page in the CMS.
If you want to customize any of the configuration options after you have added
If you want to customize any of the configuration options after you have added
the extension (or on the built-in SiteTree commenting) use `set_config_value`
```yaml
# Set the default option for pages to require login
SiteTree:
SilverStripe\CMS\Model\SiteTree:
comments:
require_login: true
```
@ -71,27 +71,29 @@ SiteTree:
```php
// Get the setting
$loginRequired = singleton('SiteTree')->getCommentsOption('require_login');
$loginRequired = singleton('SilverStripe\\CMS\\Model\\SiteTree')->getCommentsOption('require_login');
```
## HTML Comments
Comments can be configured to contain a restricted set of HTML tags through the
`html_allowed` and `html_allowed_elements` settings. Raw HTML is hardly user
friendly, but combined with a rich-text editor of your own choosing it can
Comments can be configured to contain a restricted set of HTML tags through the
`html_allowed` and `html_allowed_elements` settings. Raw HTML is hardly user
friendly, but combined with a rich-text editor of your own choosing it can
allow rich comment formatting.
In order to use this feature, you need to install the
[HTMLPurifier](http://htmlpurifier.org/) library. The easiest way to do this is
[HTMLPurifier](http://htmlpurifier.org/) library. The easiest way to do this is
through [Composer](http://getcomposer.org).
{
"require": {"ezyang/htmlpurifier": "4.*"}
}
```json
{
"require": {"ezyang/htmlpurifier": "^4.8"}
}
```
**Important**: Rendering user-provided HTML on your website always risks
exposing your users to cross-site scripting (XSS) attacks, if the HTML isn't
**Important**: Rendering user-provided HTML on your website always risks
exposing your users to cross-site scripting (XSS) attacks, if the HTML isn't
properly sanitized. Don't allow tags like `<script>` or arbitrary attributes.
## Gravatars
@ -99,49 +101,49 @@ properly sanitized. Don't allow tags like `<script>` or arbitrary attributes.
Gravatars can be turned on by adding this to your mysite/_config/config.yml file
```yaml
SiteTree:
SilverStripe\CMS\Model\SiteTree:
comments:
use_gravatar: true
````
The default size is 80 pixels, as per the gravatar site if the 's' parameter is
The default size is 80 pixels, as per the gravatar site if the 's' parameter is
omitted. To change this add the following (again to mysite/_config/config.yml):
```yaml
SiteTree:
SilverStripe\CMS\Model\SiteTree:
comments:
gravatar_size: 40
```
If the email address used to comment does not have a gravatar, it is possible
to configure the default image shown. Valid values can be found at
http://gravatar.com/site/implement/images/, and at the time of writing are the
If the email address used to comment does not have a gravatar, it is possible
to configure the default image shown. Valid values can be found at
http://gravatar.com/site/implement/images/, and at the time of writing are the
following:
* 404: do not load any image if none is associated with the email hash, instead
* 404: do not load any image if none is associated with the email hash, instead
return an HTTP 404 (File Not Found) response.
* mm: (mystery-man) a simple, cartoon-style silhouetted outline of a person
* mm: (mystery-man) a simple, cartoon-style silhouetted outline of a person
(does not vary by email hash).
* identicon: a geometric pattern based on an email hash
* monsterid: a generated 'monster' with different colors, faces, etc
* wavatar: generated faces with differing features and backgrounds
* retro: awesome generated, 8-bit arcade-style pixelated faces
* blank: a transparent PNG image (border added to HTML below for demonstration
* blank: a transparent PNG image (border added to HTML below for demonstration
purposes)
To change the default image style, add the following to mysite/_config/config.yml
```yaml
SiteTree:
SilverStripe\CMS\Model\SiteTree:
comments:
gravatar_default: 'retro'
```
The rating of the image can be changed by adding a line similar to this to
The rating of the image can be changed by adding a line similar to this to
mysite/_config/config.yml
```yaml
SiteTree:
SilverStripe\CMS\Model\SiteTree:
comments:
gravatar_rating: 'r'
```
@ -149,8 +151,8 @@ SiteTree:
Vald values for rating are as follows:
* g: suitable for display on all websites with any audience type.
* pg: may contain rude gestures, provocatively dressed individuals, the lesser
* pg: may contain rude gestures, provocatively dressed individuals, the lesser
swear words, or mild violence.
* r: may contain such things as harsh profanity, intense violence, nudity, or
* r: may contain such things as harsh profanity, intense violence, nudity, or
hard drug use.
* x: may contain hardcore sexual imagery or extremely disturbing violence.

View File

@ -18,7 +18,7 @@ After you have finished downloading the file, extract the downloaded file to you
## All
Run a database rebuild by visiting *http://yoursite.com/dev/build*. This will add the required database columns and tables for the module to function.
Run a database rebuild by visiting *http://yoursite.com/dev/build?flush=1*. This will add the required database columns and tables for the module to function, and refresh the configuration manifest.
If you previously had SilverStripe version 2.4 installed then you'll also need to run the migration script provided. More information on this is provided in the next section.
@ -34,4 +34,4 @@ For more configuration options see [Configuration](Configuration.md).
This module replaces the built-in commenting system available in versions up to SilverStripe 2.4. To migrate from that you'll need to run `dev/build` after installing the module.
You can do this via sake (`sake dev/build`) or via a web browser by visiting `http://yoursite.com/dev/build`
You can do this via sake (`sake dev/build flush=1`) or via a web browser by visiting `http://yoursite.com/dev/build?flush=1`

View File

@ -1,5 +1,17 @@
<?php
namespace SilverStripe\Comments\Admin;
use SilverStripe\Admin\LeftAndMain;
use SilverStripe\Comments\Admin\CommentsGridField;
use SilverStripe\Comments\Model\Comment;
use SilverStripe\Forms\Tab;
use SilverStripe\Forms\TabSet;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Form;
use SilverStripe\Security\PermissionProvider;
use SilverStripe\Security\Security;
/**
* Comment administration system within the CMS
*

View File

@ -1,5 +1,10 @@
<?php
namespace SilverStripe\Comments\Admin;
use SilverStripe\Forms\FormField;
use SilverStripe\Forms\GridField\GridField;
class CommentsGridField extends GridField
{
/**

View File

@ -1,5 +1,14 @@
<?php
namespace SilverStripe\Comments\Admin;
use SilverStripe\Comments\Model\Comment;
use SilverStripe\Control\Controller;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridField_ActionProvider;
use SilverStripe\Forms\GridField\GridField_ColumnProvider;
use SilverStripe\Forms\GridField\GridField_FormAction;
class CommentsGridFieldAction implements GridField_ColumnProvider, GridField_ActionProvider
{
/**
@ -47,7 +56,7 @@ class CommentsGridFieldAction implements GridField_ColumnProvider, GridField_Act
return;
}
$field = "";
$field = '';
if (!$record->IsSpam || !$record->Moderated) {
$field .= GridField_FormAction::create(
@ -86,7 +95,7 @@ class CommentsGridFieldAction implements GridField_ColumnProvider, GridField_Act
public function handleAction(GridField $gridField, $actionName, $arguments, $data)
{
if ($actionName == 'spam') {
$comment = Comment::get()->byID($arguments["RecordID"]);
$comment = Comment::get()->byID($arguments['RecordID']);
$comment->markSpam();
// output a success message to the user
@ -97,7 +106,7 @@ class CommentsGridFieldAction implements GridField_ColumnProvider, GridField_Act
}
if ($actionName == 'approve') {
$comment = Comment::get()->byID($arguments["RecordID"]);
$comment = Comment::get()->byID($arguments['RecordID']);
$comment->markApproved();
// output a success message to the user

View File

@ -1,20 +1,19 @@
<?php
/**
* @package comments
*/
class CommentsGridFieldBulkAction extends GridFieldBulkActionHandler
{
}
namespace SilverStripe\Comments\Admin\CommentsGridFieldBulkAction;
use Colymba\BulkManager\BulkAction\Handler as GridFieldBulkActionHandler;
use SilverStripe\Core\Convert;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
/**
* A {@link GridFieldBulkActionHandler} for bulk marking comments as spam
*
* @package comments
*/
class CommentsGridFieldBulkAction_Handlers extends CommentsGridFieldBulkAction
class Handler extends GridFieldBulkActionHandler
{
private static $allowed_actions = array(
'spam',
'approve',
@ -25,8 +24,11 @@ class CommentsGridFieldBulkAction_Handlers extends CommentsGridFieldBulkAction
'approve' => 'approve',
);
public function spam(SS_HTTPRequest $request)
/**
* @param HTTPRequest $request
* @return HTTPResponse
*/
public function spam(HTTPRequest $request)
{
$ids = array();
@ -35,7 +37,7 @@ class CommentsGridFieldBulkAction_Handlers extends CommentsGridFieldBulkAction
$record->markSpam();
}
$response = new SS_HTTPResponse(Convert::raw2json(array(
$response = new HTTPResponse(Convert::raw2json(array(
'done' => true,
'records' => $ids
)));
@ -45,8 +47,11 @@ class CommentsGridFieldBulkAction_Handlers extends CommentsGridFieldBulkAction
return $response;
}
public function approve(SS_HTTPRequest $request)
/**
* @param HTTPRequest $request
* @return HTTPResponse
*/
public function approve(HTTPRequest $request)
{
$ids = array();
@ -55,7 +60,7 @@ class CommentsGridFieldBulkAction_Handlers extends CommentsGridFieldBulkAction
$record->markApproved();
}
$response = new SS_HTTPResponse(Convert::raw2json(array(
$response = new HTTPResponse(Convert::raw2json(array(
'done' => true,
'records' => $ids
)));

View File

@ -1,5 +1,13 @@
<?php
namespace SilverStripe\Comments\Admin;
use Colymba\BulkManager\BulkManager;
use SilverStripe\Comments\Admin\CommentsGridFieldBulkAction\Handler;
use SilverStripe\Core\Convert;
use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor;
use SilverStripe\Forms\GridField\GridFieldDataColumns;
class CommentsGridFieldConfig extends GridFieldConfig_RecordEditor
{
public function __construct($itemsPerPage = 25)
@ -11,7 +19,7 @@ class CommentsGridFieldConfig extends GridFieldConfig_RecordEditor
$this->addComponent(new CommentsGridFieldAction());
// Format column
$columns = $this->getComponentByType('GridFieldDataColumns');
$columns = $this->getComponentByType(GridFieldDataColumns::class);
$columns->setFieldFormatting(array(
'ParentTitle' => function ($value, &$item) {
return sprintf(
@ -23,12 +31,12 @@ class CommentsGridFieldConfig extends GridFieldConfig_RecordEditor
));
// Add bulk option
$manager = new GridFieldBulkManager();
$manager = new BulkManager();
$manager->addBulkAction(
'spam',
_t('CommentsGridFieldConfig.SPAM', 'Spam'),
'CommentsGridFieldBulkAction_Handlers',
'spam',
_t('CommentsGridFieldConfig.SPAM', 'Spam'),
Handler::class,
array(
'isAjax' => true,
'icon' => 'cross',
@ -37,9 +45,9 @@ class CommentsGridFieldConfig extends GridFieldConfig_RecordEditor
);
$manager->addBulkAction(
'approve',
_t('CommentsGridFieldConfig.APPROVE', 'Approve'),
'CommentsGridFieldBulkAction_Handlers',
'approve',
_t('CommentsGridFieldConfig.APPROVE', 'Approve'),
Handler::class,
array(
'isAjax' => true,
'icon' => 'cross',

View File

@ -1,12 +1,42 @@
<?php
namespace SilverStripe\Comments\Controllers;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Comments\Extensions\CommentsExtension;
use SilverStripe\Comments\Model\Comment;
use SilverStripe\Control\Cookie;
use SilverStripe\Control\Director;
use SilverStripe\Control\Controller;
use SilverStripe\Control\Email\Email;
use SilverStripe\Control\HTTP;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\RSS\RSSFeed;
use SilverStripe\Control\Session;
use SilverStripe\Core\Convert;
use SilverStripe\Forms\CompositeField;
use SilverStripe\Forms\EmailField;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Form;
use SilverStripe\Forms\FormAction;
use SilverStripe\Forms\HiddenField;
use SilverStripe\Forms\ReadonlyField;
use SilverStripe\Forms\RequiredFields;
use SilverStripe\Forms\TextareaField;
use SilverStripe\Forms\TextField;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\PaginatedList;
use SilverStripe\Security\Member;
use SilverStripe\Security\Security;
/**
* @package comments
*/
class CommentingController extends Controller
{
/**
* {@inheritDoc}
*/
private static $allowed_actions = array(
'delete',
'spam',
@ -19,6 +49,9 @@ class CommentingController extends Controller
'doPreviewComment'
);
/**
* {@inheritDoc}
*/
private static $url_handlers = array(
'reply/$ParentCommentID//$ID/$OtherID' => 'reply',
);
@ -36,11 +69,11 @@ class CommentingController extends Controller
);
/**
* Base class this commenting form is for
* Parent class this commenting form is for
*
* @var string
*/
private $baseClass = "";
private $parentClass = '';
/**
* The record this commenting form is for
@ -64,23 +97,45 @@ class CommentingController extends Controller
protected $fallbackReturnURL = null;
/**
* Set the base class to use
* Set the parent class name to use
*
* @param string $class
*/
public function setBaseClass($class)
public function setParentClass($class)
{
$this->baseClass = $class;
$this->parentClass = $this->encodeClassName($class);
}
/**
* Get the base class used
* Get the parent class name used
*
* @return string
*/
public function getBaseClass()
public function getParentClass()
{
return $this->baseClass;
return $this->decodeClassName($this->parentClass);
}
/**
* Encode a fully qualified class name to a URL-safe version
*
* @param string $input
* @return string
*/
public function encodeClassName($input)
{
return str_replace('\\', '-', $input);
}
/**
* Decode an "encoded" fully qualified class name back to its original
*
* @param string $input
* @return string
*/
public function decodeClassName($input)
{
return str_replace('-', '\\', $input);
}
/**
@ -137,22 +192,25 @@ class CommentingController extends Controller
}
// Otherwise a singleton of that record
if ($class = $this->getBaseClass()) {
if ($class = $this->getParentClass()) {
return singleton($class)->getCommentsOption($key);
}
// Otherwise just use the default options
return singleton('CommentsExtension')->getCommentsOption($key);
return singleton(CommentsExtension::class)->getCommentsOption($key);
}
/**
* Workaround for generating the link to this controller
*
* @param string $action
* @param int $id
* @param string $other
* @return string
*/
public function Link($action = '', $id = '', $other = '')
{
return Controller::join_links(Director::baseURL(), __CLASS__, $action, $id, $other);
return Controller::join_links(Director::baseURL(), 'comments', $action, $id, $other);
}
/**
@ -169,23 +227,19 @@ class CommentingController extends Controller
* Return an RSSFeed of comments for a given set of comments or all
* comments on the website.
*
* To maintain backwards compatibility with 2.4 this supports mapping
* of PageComment/rss?pageid= as well as the new RSS format for comments
* of CommentingController/rss/{classname}/{id}
*
* @param SS_HTTPRequest
* @param HTTPRequest
*
* @return RSSFeed
*/
public function getFeed(SS_HTTPRequest $request)
public function getFeed(HTTPRequest $request)
{
$link = $this->Link('rss');
$class = $request->param('ID');
$class = $this->decodeClassName($request->param('ID'));
$id = $request->param('OtherID');
// Support old pageid param
if (!$id && !$class && ($id = $request->getVar('pageid'))) {
$class = 'SiteTree';
$class = SiteTree::class;
}
$comments = Comment::get()->filter(array(
@ -195,12 +249,12 @@ class CommentingController extends Controller
// Check if class filter
if ($class) {
if (!is_subclass_of($class, 'DataObject') || !$class::has_extension('CommentsExtension')) {
if (!is_subclass_of($class, DataObject::class) || !$class::has_extension(CommentsExtension::class)) {
return $this->httpError(404);
}
$this->setBaseClass($class);
$comments = $comments->filter('BaseClass', $class);
$link = Controller::join_links($link, $class);
$this->setParentClass($class);
$comments = $comments->filter('ParentClass', $class);
$link = Controller::join_links($link, $this->encodeClassName($class));
// Check if id filter
if ($id) {
@ -211,7 +265,6 @@ class CommentingController extends Controller
}
$title = _t('CommentingController.RSSTITLE', "Comments RSS Feed");
$comments = new PaginatedList($comments, $request);
$comments->setPageLength($this->getOption('comments_per_page'));
@ -220,7 +273,9 @@ class CommentingController extends Controller
$link,
$title,
$link,
'Title', 'EscapedComment', 'AuthorName'
'Title',
'EscapedComment',
'AuthorName'
);
}
@ -302,7 +357,6 @@ class CommentingController extends Controller
if (!$comment->getSecurityToken()->checkRequest($this->request)) {
return $this->httpError(400);
}
$comment->markApproved();
return $this->renderChangedCommentState($comment);
}
@ -318,7 +372,7 @@ class CommentingController extends Controller
// Render comment using AJAX
if ($this->request->isAjax()) {
return $comment->renderWith('CommentsInterface_singlecomment');
return $comment->renderWith('Includes/CommentsInterface_singlecomment');
} else {
// Redirect to either the comment or start of the page
if (empty($referer)) {
@ -345,10 +399,8 @@ class CommentingController extends Controller
public function getComment()
{
$id = isset($this->urlParams['ID']) ? $this->urlParams['ID'] : false;
if ($id) {
$comment = DataObject::get_by_id('Comment', $id);
$comment = Comment::get()->byId($id);
if ($comment) {
$this->fallbackReturnURL = $comment->Link();
return $comment;
@ -361,13 +413,14 @@ class CommentingController extends Controller
/**
* Create a reply form for a specified comment
*
* @param Comment $comment
* @param Comment $comment
* @return Form
*/
public function ReplyForm($comment)
{
// Enables multiple forms with different names to use the same handler
$form = $this->CommentsForm();
$form->setName('ReplyForm_'.$comment->ID);
$form->setName('ReplyForm_' . $comment->ID);
$form->addExtraClass('reply-form');
// Load parent into reply form
@ -387,13 +440,14 @@ class CommentingController extends Controller
* Request handler for reply form.
* This method will disambiguate multiple reply forms in the same method
*
* @param SS_HTTPRequest $request
* @param HTTPRequest $request
* @throws HTTPResponse_Exception
*/
public function reply(SS_HTTPRequest $request)
public function reply(HTTPRequest $request)
{
// Extract parent comment from reply and build this way
if ($parentID = $request->param('ParentCommentID')) {
$comment = DataObject::get_by_id('Comment', $parentID, true);
$comment = DataObject::get_by_id(Comment::class, $parentID, true);
if ($comment) {
return $this->ReplyForm($comment);
}
@ -419,34 +473,31 @@ class CommentingController extends Controller
$fields = new FieldList(
$dataFields = new CompositeField(
// Name
TextField::create("Name", _t('CommentInterface.YOURNAME', 'Your name'))
$a = TextField::create('Name', _t('CommentInterface.YOURNAME', 'Your name'))
->setCustomValidationMessage($nameRequired)
->setAttribute('data-msg-required', $nameRequired),
// Email
EmailField::create(
"Email",
_t('CommentingController.EMAILADDRESS', "Your email address (will not be published)")
'Email',
_t('CommentingController.EMAILADDRESS', 'Your email address (will not be published)')
)
->setCustomValidationMessage($emailRequired)
->setAttribute('data-msg-required', $emailRequired)
->setAttribute('data-msg-email', $emailInvalid)
->setAttribute('data-rule-email', true),
// Url
TextField::create("URL", _t('CommentingController.WEBSITEURL', "Your website URL"))
TextField::create('URL', _t('CommentingController.WEBSITEURL', 'Your website URL'))
->setAttribute('data-msg-url', $urlInvalid)
->setAttribute('data-rule-url', true),
// Comment
TextareaField::create("Comment", _t('CommentingController.COMMENTS', "Comments"))
TextareaField::create('Comment', _t('CommentingController.COMMENTS', 'Comments'))
->setCustomValidationMessage($commentRequired)
->setAttribute('data-msg-required', $commentRequired)
),
HiddenField::create("ParentID"),
HiddenField::create("ReturnURL"),
HiddenField::create("ParentCommentID"),
HiddenField::create("BaseClass")
HiddenField::create('ParentID'),
HiddenField::create('ParentClassName'),
HiddenField::create('ReturnURL'),
HiddenField::create('ParentCommentID')
);
// Preview formatted comment. Makes most sense when shortcodes or
@ -463,7 +514,7 @@ class CommentingController extends Controller
// save actions
$actions = new FieldList(
new FormAction("doPostComment", _t('CommentInterface.POST', 'Post'))
$postAction = new FormAction('doPostComment', _t('CommentInterface.POST', 'Post'))
);
if ($usePreview) {
$actions->push(
@ -481,7 +532,6 @@ class CommentingController extends Controller
// if the record exists load the extra required data
if ($record = $this->getOwnerRecord()) {
// Load member data
$member = Member::currentUser();
if (($record->CommentsRequireLogin || $record->PostingRequiredPermission) && $member) {
@ -489,17 +539,24 @@ class CommentingController extends Controller
$fields->removeByName('Name');
$fields->removeByName('Email');
$fields->insertBefore(new ReadonlyField("NameView", _t('CommentInterface.YOURNAME', 'Your name'), $member->getName()), 'URL');
$fields->push(new HiddenField("Name", "", $member->getName()));
$fields->push(new HiddenField("Email", "", $member->Email));
$fields->insertBefore(
new ReadonlyField(
'NameView',
_t('CommentInterface.YOURNAME', 'Your name'),
$member->getName()
),
'URL'
);
$fields->push(new HiddenField('Name', '', $member->getName()));
$fields->push(new HiddenField('Email', '', $member->Email));
}
// we do not want to read a new URL when the form has already been submitted
// which in here, it hasn't been.
$form->loadDataFrom(array(
'ParentID' => $record->ID,
'ReturnURL' => $this->request->getURL(),
'BaseClass' => $this->getBaseClass()
'ParentID' => $record->ID,
'ReturnURL' => $this->request->getURL(),
'ParentClassName' => $this->getParentClass()
));
}
@ -511,14 +568,14 @@ class CommentingController extends Controller
$data = Convert::json2array($data);
$form->loadDataFrom(array(
"Name" => isset($data['Name']) ? $data['Name'] : '',
"URL" => isset($data['URL']) ? $data['URL'] : '',
"Email" => isset($data['Email']) ? $data['Email'] : ''
'Name' => isset($data['Name']) ? $data['Name'] : '',
'URL' => isset($data['URL']) ? $data['URL'] : '',
'Email' => isset($data['Email']) ? $data['Email'] : ''
));
// allow previous value to fill if comment not stored in cookie (i.e. validation error)
$prevComment = Cookie::get('CommentsForm_Comment');
if ($prevComment && $prevComment != '') {
$form->loadDataFrom(array("Comment" => $prevComment));
$form->loadDataFrom(array('Comment' => $prevComment));
}
}
@ -535,24 +592,26 @@ class CommentingController extends Controller
/**
* Process which creates a {@link Comment} once a user submits a comment from this form.
*
* @param array $data
* @param Form $form
* @param array $data
* @param Form $form
* @return HTTPResponse
*/
public function doPostComment($data, $form)
{
// Load class and parent from data
if (isset($data['BaseClass'])) {
$this->setBaseClass($data['BaseClass']);
if (isset($data['ParentClassName'])) {
$this->setParentClass($data['ParentClassName']);
}
if (isset($data['ParentID']) && ($class = $this->getBaseClass())) {
if (isset($data['ParentID']) && ($class = $this->getParentClass())) {
$this->setOwnerRecord($class::get()->byID($data['ParentID']));
}
if (!$this->getOwnerRecord()) {
return $this->httpError(404);
}
// cache users data
Cookie::set("CommentsForm_UserData", Convert::raw2json($data));
Cookie::set("CommentsForm_Comment", $data['Comment']);
Cookie::set('CommentsForm_UserData', Convert::raw2json($data));
Cookie::set('CommentsForm_Comment', $data['Comment']);
// extend hook to allow extensions. Also see onAfterPostComment
$this->extend('onBeforePostComment', $form);
@ -564,13 +623,13 @@ class CommentingController extends Controller
_t(
'CommentingController.PERMISSIONFAILURE',
"You're not able to post comments to this page. Please ensure you are logged in and have an "
. "appropriate permission level."
. 'appropriate permission level.'
)
);
}
if ($member = Member::currentUser()) {
$form->Fields()->push(new HiddenField("AuthorID", "Author ID", $member->ID));
$form->Fields()->push(new HiddenField('AuthorID', 'Author ID', $member->ID));
}
// What kind of moderation is required?
@ -590,6 +649,9 @@ class CommentingController extends Controller
$comment = new Comment();
$form->saveInto($comment);
$comment->ParentID = $data['ParentID'];
$comment->ParentClass = $data['ParentClassName'];
$comment->AllowHtml = $this->getOption('html_allowed');
$comment->Moderated = !$requireModeration;
@ -616,7 +678,7 @@ class CommentingController extends Controller
// Find parent link
if (!empty($data['ReturnURL'])) {
$url = $data['ReturnURL'];
} elseif ($parent = $comment->getParent()) {
} elseif ($parent = $comment->Parent()) {
$url = $parent->Link();
} else {
return $this->redirectBack();
@ -628,7 +690,7 @@ class CommentingController extends Controller
$hash = $form->FormName();
} elseif (!$comment->Moderated) {
// Display the "awaiting moderation" text
$hash = "moderated";
$hash = 'moderated';
} else {
// Link to the moderated, non-spam comment
$hash = $comment->Permalink();
@ -637,6 +699,11 @@ class CommentingController extends Controller
return $this->redirect(Controller::join_links($url, "#{$hash}"));
}
/**
* @param array $data
* @param Form $form
* @return HTTPResponse
*/
public function doPreviewComment($data, $form)
{
$data['IsPreview'] = 1;
@ -644,6 +711,9 @@ class CommentingController extends Controller
return $this->doPostComment($data, $form);
}
/**
* @return HTTPResponse|false
*/
public function redirectBack()
{
// Don't cache the redirect back ever

View File

@ -1,5 +1,28 @@
<?php
namespace SilverStripe\Comments\Extensions;
use SilverStripe\Comments\Admin\CommentsGridField;
use SilverStripe\Comments\Admin\CommentsGridFieldConfig;
use SilverStripe\Comments\Controllers\CommentingController;
use SilverStripe\Comments\Model\Comment;
use SilverStripe\Control\Controller;
use SilverStripe\Control\Director;
use SilverStripe\Control\Session;
use SilverStripe\Core\Config\Config;
use SilverStripe\Dev\Deprecation;
use SilverStripe\Forms\CheckboxField;
use SilverStripe\Forms\DropdownField;
use SilverStripe\Forms\FieldGroup;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Tab;
use SilverStripe\Forms\TabSet;
use SilverStripe\ORM\DataExtension;
use SilverStripe\ORM\PaginatedList;
use SilverStripe\Security\Member;
use SilverStripe\Security\Permission;
use SilverStripe\View\Requirements;
/**
* Extension to {@link DataObject} to enable tracking comments.
*
@ -75,6 +98,13 @@ class CommentsExtension extends DataExtension
'CommentsRequireLogin' => 'Boolean',
);
/**
* {@inheritDoc}
*/
private static $has_many = [
'Commments' => 'SilverStripe\\Comments\\Model\\Comment.Parent'
];
/**
* CMS configurable options should default to the config values, but respect
* default values specified by the object
@ -204,13 +234,13 @@ class CommentsExtension extends DataExtension
* Returns the RelationList of all comments against this object. Can be used as a data source
* for a gridfield with write access.
*
* @return CommentList
* @return DataList
*/
public function AllComments()
{
$order = $this->owner->getCommentsOption('order_comments_by');
$comments = CommentList::create($this->ownerBaseClass)
->forForeignID($this->owner->ID)
$comments = Comment::get()
->filter('ParentID', $this->owner->ID)
->sort($order);
$this->owner->extend('updateAllComments', $comments);
return $comments;
@ -219,7 +249,7 @@ class CommentsExtension extends DataExtension
/**
* Returns all comments against this object, with with spam and unmoderated items excluded, for use in the frontend
*
* @return CommentList
* @return DataList
*/
public function AllVisibleComments()
{
@ -245,7 +275,7 @@ class CommentsExtension extends DataExtension
/**
* Returns the root level comments, with spam and unmoderated items excluded, for use in the frontend
*
* @return CommentList
* @return DataList
*/
public function Comments()
{
@ -279,20 +309,6 @@ class CommentsExtension extends DataExtension
return $list;
}
/**
* Check if comments are configured for this page even if they are currently disabled.
* Do not include the comments on pages which don't have id's such as security pages
*
* @deprecated since version 2.0
*
* @return boolean
*/
public function getCommentsConfigured()
{
Deprecation::notice('2.0', 'getCommentsConfigured is deprecated. Use getCommentsEnabled instead');
return true; // by virtue of all classes with this extension being 'configured'
}
/**
* Determine if comments are enabled for this instance
*
@ -323,15 +339,6 @@ class CommentsExtension extends DataExtension
return $this->owner->getCommentsOption('comments_holder_id');
}
/**
* @deprecated since version 2.0
*/
public function getPostingRequiresPermission()
{
Deprecation::notice('2.0', 'Use getPostingRequiredPermission instead');
return $this->getPostingRequiredPermission();
}
/**
* Permission codes required in order to post (or empty if none required)
*
@ -342,12 +349,6 @@ class CommentsExtension extends DataExtension
return $this->owner->getCommentsOption('required_permission');
}
public function canPost()
{
Deprecation::notice('2.0', 'Use canPostComment instead');
return $this->canPostComment();
}
/**
* Determine if a user can post comments on this item
*
@ -401,12 +402,6 @@ class CommentsExtension extends DataExtension
return $this->owner->canEdit($member);
}
public function getRssLink()
{
Deprecation::notice('2.0', 'Use getCommentRSSLink instead');
return $this->getCommentRSSLink();
}
/**
* Gets the RSS link to all comments
*
@ -414,13 +409,7 @@ class CommentsExtension extends DataExtension
*/
public function getCommentRSSLink()
{
return Controller::join_links(Director::baseURL(), 'CommentingController/rss');
}
public function getRssLinkPage()
{
Deprecation::notice('2.0', 'Use getCommentRSSLinkPage instead');
return $this->getCommentRSSLinkPage();
return Director::absoluteURL('comments/rss');
}
/**
@ -431,7 +420,9 @@ class CommentsExtension extends DataExtension
public function getCommentRSSLinkPage()
{
return Controller::join_links(
$this->getCommentRSSLink(), $this->ownerBaseClass, $this->owner->ID
$this->getCommentRSSLink(),
str_replace('\\', '-', $this->ownerBaseClass),
$this->owner->ID
);
}
@ -451,9 +442,9 @@ class CommentsExtension extends DataExtension
// Check if enabled
$enabled = $this->getCommentsEnabled();
if ($enabled && $this->owner->getCommentsOption('include_js')) {
Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js');
Requirements::javascript(THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js');
Requirements::javascript(THIRDPARTY_DIR . '/jquery-validate/lib/jquery.form.js');
Requirements::javascript(ADMIN_THIRDPARTY_DIR . '/jquery/jquery.js');
Requirements::javascript(ADMIN_THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js');
Requirements::javascript(ADMIN_THIRDPARTY_DIR . '/jquery-form/jquery.form.js');
Requirements::javascript(COMMENTS_THIRDPARTY . '/jquery-validate/jquery.validate.min.js');
Requirements::add_i18n_javascript('comments/javascript/lang');
Requirements::javascript('comments/javascript/CommentsInterface.js');
@ -461,7 +452,7 @@ class CommentsExtension extends DataExtension
$controller = CommentingController::create();
$controller->setOwnerRecord($this->owner);
$controller->setBaseClass($this->ownerBaseClass);
$controller->setParentClass($this->owner->getClassName());
$controller->setOwnerController(Controller::curr());
$moderatedSubmitted = Session::get('CommentsModerated');
@ -489,17 +480,7 @@ class CommentsExtension extends DataExtension
{
$class = $this->ownerBaseClass;
return (is_subclass_of($class, 'SiteTree')) || ($class == 'SiteTree');
}
/**
* @deprecated 1.0 Please use {@link CommentsExtension->CommentsForm()}
*/
public function PageComments()
{
// This method is very commonly used, don't throw a warning just yet
Deprecation::notice('1.0', '$PageComments is deprecated. Please use $CommentsForm');
return $this->CommentsForm();
return (is_subclass_of($class, SiteTree::class)) || ($class == SiteTree::class);
}
/**

View File

@ -1,5 +1,31 @@
<?php
namespace SilverStripe\Comments\Model;
use HTMLPurifier_Config;
use HTMLPurifier;
use SilverStripe\Comments\Controllers\CommentingController;
use SilverStripe\Comments\Extensions\CommentsExtension;
use SilverStripe\Comments\Model\Comment\SecurityToken;
use SilverStripe\Control\Controller;
use SilverStripe\Control\Director;
use SilverStripe\Core\Email\Email;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Forms\CheckboxField;
use SilverStripe\Forms\EmailField;
use SilverStripe\Forms\FieldGroup;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\HeaderField;
use SilverStripe\Forms\HTMLEditor\HTMLEditorField;
use SilverStripe\Forms\TextareaField;
use SilverStripe\Forms\TextField;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DB;
use SilverStripe\ORM\PaginatedList;
use SilverStripe\Security\Member;
use SilverStripe\Security\Permission;
/**
* Represents a single comment object.
*
@ -22,40 +48,53 @@
*/
class Comment extends DataObject
{
/**
* @var array
* {@inheritDoc}
*/
private static $db = array(
'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)',
'Depth' => 'Int',
'Depth' => 'Int'
);
/**
* {@inheritDoc}
*/
private static $has_one = array(
"Author" => "Member",
"ParentComment" => "Comment",
'Author' => Member::class,
'ParentComment' => self::class,
'Parent' => DataObject::class
);
/**
* {@inheritDoc}
*/
private static $has_many = array(
"ChildComments" => "Comment"
'ChildComments' => self::class
);
/**
* {@inheritDoc}
*/
private static $default_sort = '"Created" DESC';
/**
* {@inheritDoc}
*/
private static $defaults = array(
'Moderated' => 0,
'IsSpam' => 0,
);
/**
* {@inheritDoc}
*/
private static $casting = array(
'Title' => 'Varchar',
'ParentTitle' => 'Varchar',
@ -66,30 +105,46 @@ class Comment extends DataObject
'SpamLink' => 'Varchar',
'HamLink' => 'Varchar',
'ApproveLink' => 'Varchar',
'Permalink' => 'Varchar',
'Permalink' => 'Varchar'
);
/**
* {@inheritDoc}
*/
private static $searchable_fields = array(
'Name',
'Email',
'Comment',
'Created',
'BaseClass',
'Created'
);
/**
* {@inheritDoc}
*/
private static $summary_fields = array(
'Name' => 'Submitted By',
'Email' => 'Email',
'Comment.LimitWordCount' => 'Comment',
'Created' => 'Date Posted',
'ParentTitle' => 'Post',
'IsSpam' => 'Is Spam',
'Parent.Title' => 'Post',
'IsSpam' => 'Is Spam'
);
/**
* {@inheritDoc}
*/
private static $field_labels = array(
'Author' => 'Author Member',
'Author' => 'Author Member'
);
/**
* {@inheritDoc}
*/
private static $table_name = 'Comment';
/**
* {@inheritDoc}
*/
public function onBeforeWrite()
{
parent::onBeforeWrite();
@ -103,6 +158,9 @@ class Comment extends DataObject
$this->updateDepth();
}
/**
* {@inheritDoc}
*/
public function onBeforeDelete()
{
parent::onBeforeDelete();
@ -118,7 +176,7 @@ class Comment extends DataObject
*/
public function getSecurityToken()
{
return Injector::inst()->createWithArgs('Comment_SecurityToken', array($this));
return Injector::inst()->createWithArgs(SecurityToken::class, array($this));
}
/**
@ -128,7 +186,7 @@ class Comment extends DataObject
{
parent::requireDefaultRecords();
if (DB::getConn()->hasTable('PageComment')) {
if (DB::get_schema()->hasTable('PageComment')) {
$comments = DB::query('SELECT * FROM "PageComment"');
if ($comments) {
@ -138,7 +196,7 @@ class Comment extends DataObject
$comment->update($pageComment);
// set the variables which have changed
$comment->BaseClass = 'SiteTree';
$comment->BaseClass = SiteTree::class;
$comment->URL = (isset($pageComment['CommenterURL'])) ? $pageComment['CommenterURL'] : '';
if ((int) $pageComment['NeedsModeration'] == 0) {
$comment->Moderated = true;
@ -149,7 +207,7 @@ class Comment extends DataObject
}
DB::alteration_message('Migrated PageComment to Comment', 'changed');
DB::getConn()->dontRequireTable('PageComment');
DB::get_schema()->dontRequireTable('PageComment');
}
}
@ -162,7 +220,7 @@ class Comment extends DataObject
*/
public function Link($action = '')
{
if ($parent = $this->getParent()) {
if ($parent = $this->Parent()) {
return $parent->Link($action) . '#' . $this->Permalink();
}
}
@ -212,22 +270,25 @@ class Comment extends DataObject
public function getOption($key)
{
// If possible use the current record
$record = $this->getParent();
$record = $this->Parent();
if (!$record && $this->BaseClass) {
if (!$record && $this->Parent()) {
// Otherwise a singleton of that record
$record = singleton($this->BaseClass);
$record = singleton($this->Parent()->dataClass());
} elseif (!$record) {
// Otherwise just use the default options
$record = singleton('CommentsExtension');
$record = singleton(CommentsExtension::class);
}
return ($record->hasMethod('getCommentsOption')) ? $record->getCommentsOption($key) : null;
return ($record instanceof CommentsExtension || $record->hasExtension(CommentsExtension::class))
? $record->getCommentsOption($key)
: null;
}
/**
* Returns the parent {@link DataObject} this comment is attached too
*
* @deprecated 4.0.0 Use $this->Parent() instead
* @return DataObject
*/
public function getParent()
@ -245,7 +306,7 @@ class Comment extends DataObject
*/
public function getParentTitle()
{
if ($parent = $this->getParent()) {
if ($parent = $this->Parent()) {
return $parent->Title ?: ($parent->ClassName . ' #' . $parent->ID);
}
}
@ -257,13 +318,16 @@ class Comment extends DataObject
*/
public function getParentClassName()
{
return $this->BaseClass;
return $this->Parent()->getClassName();
}
/**
* {@inheritDoc}
*/
public function castingHelper($field)
{
// Safely escape the comment
if ($field === 'EscapedComment') {
if (in_array($field, ['EscapedComment', 'Comment'], true)) {
return $this->AllowHtml ? 'HTMLText' : 'Text';
}
return parent::castingHelper($field);
@ -293,10 +357,10 @@ class Comment extends DataObject
* @todo needs to compare to the new {@link Commenting} configuration API
*
* @param Member $member
*
* @param array $context
* @return bool
*/
public function canCreate($member = null)
public function canCreate($member = null, $context = [])
{
return false;
}
@ -306,7 +370,6 @@ class Comment extends DataObject
* flag being set to true.
*
* @param Member $member
*
* @return Boolean
*/
public function canView($member = null)
@ -322,9 +385,9 @@ class Comment extends DataObject
return true;
}
if ($parent = $this->getParent()) {
if ($parent = $this->Parent()) {
return $parent->canView($member)
&& $parent->has_extension('CommentsExtension')
&& $parent->hasExtension(CommentsExtension::class)
&& $parent->CommentsEnabled;
}
@ -335,7 +398,6 @@ class Comment extends DataObject
* Checks if the comment can be edited.
*
* @param null|int|Member $member
*
* @return Boolean
*/
public function canEdit($member = null)
@ -355,7 +417,7 @@ class Comment extends DataObject
return true;
}
if ($parent = $this->getParent()) {
if ($parent = $this->Parent()) {
return $parent->canEdit($member);
}
@ -366,7 +428,6 @@ class Comment extends DataObject
* Checks if the comment can be deleted.
*
* @param null|int|Member $member
*
* @return Boolean
*/
public function canDelete($member = null)
@ -398,7 +459,7 @@ class Comment extends DataObject
}
if (is_numeric($member)) {
$member = DataObject::get_by_id('Member', $member, true);
$member = DataObject::get_by_id(Member::class, $member, true);
}
return $member;
@ -435,9 +496,17 @@ class Comment extends DataObject
return false;
}
/**
* @todo: How do we handle "DataObject" instances that don't have a Link to reject/spam/delete?? This may
* we have to make CMS a hard dependency instead.
*/
// if (!$this->Parent()->hasMethod('Link')) {
// return false;
// }
$url = Controller::join_links(
Director::baseURL(),
'CommentingController',
'comments',
$action,
$this->ID
);
@ -556,7 +625,7 @@ class Comment extends DataObject
{
$title = sprintf(_t('Comment.COMMENTBY', 'Comment by %s', 'Name'), $this->getAuthorName());
if ($parent = $this->getParent()) {
if ($parent = $this->Parent()) {
if ($parent->Title) {
$title .= sprintf(' %s %s', _t('Comment.ON', 'on'), $parent->Title);
}
@ -570,7 +639,7 @@ class Comment extends DataObject
*/
public function getCMSFields()
{
$commentField = $this->AllowHtml ? 'HtmlEditorField' : 'TextareaField';
$commentField = $this->AllowHtml ? HTMLEditorField::class : TextareaField::class;
$fields = new FieldList(
$this
->obj('Created')
@ -610,8 +679,8 @@ class Comment extends DataObject
// FIXME - the method setName in DatetimeField is not chainable, hence
// the lack of chaining here
$createdField = $parent
->obj('Created')
->scaffoldFormField($parent->fieldLabel('Created'));
->obj('Created')
->scaffoldFormField($parent->fieldLabel('Created'));
$createdField->setName('ParentComment_Created');
$createdField->setValue($parent->Created);
$createdField->performReadonlyTransformation();
@ -631,7 +700,7 @@ class Comment extends DataObject
$fields->push(
$parent
->obj('EscapedComment')
->scaffoldFormField($parent->fieldLabel('Comment'))
->scaffoldFormField($parent->fieldLabel(self::class))
->setName('ParentComment_EscapedComment')
->setValue($parent->Comment)
->performReadonlyTransformation()
@ -643,9 +712,9 @@ class Comment extends DataObject
}
/**
* @param String $dirtyHtml
* @param string $dirtyHtml
*
* @return String
* @return string
*/
public function purifyHtml($dirtyHtml)
{
@ -659,8 +728,10 @@ class Comment extends DataObject
public function getHtmlPurifierService()
{
$config = HTMLPurifier_Config::createDefault();
$allowedElements = $this->getOption('html_allowed_elements');
$config->set('HTML.AllowedElements', $allowedElements);
$allowedElements = (array) $this->getOption('html_allowed_elements');
if (!empty($allowedElements)) {
$config->set('HTML.AllowedElements', $allowedElements);
}
// This injector cannot be set unless the 'p' element is allowed
if (in_array('p', $allowedElements)) {
@ -748,7 +819,7 @@ class Comment extends DataObject
$list = $this->AllReplies();
// Filter spam comments for non-administrators if configured
$parent = $this->getParent();
$parent = $this->Parent();
$showSpam = $this->getOption('frontend_spam') && $parent && $parent->canModerateComments();
if (!$showSpam) {
$list = $list->filter('IsSpam', 0);
@ -778,7 +849,7 @@ class Comment extends DataObject
// Add pagination
$list = new PaginatedList($list, Controller::curr()->getRequest());
$list->setPaginationGetVar('repliesstart'.$this->ID);
$list->setPaginationGetVar('repliesstart' . $this->ID);
$list->setPageLength($this->getOption('comments_per_page'));
$this->extend('updatePagedReplies', $list);
@ -798,7 +869,7 @@ class Comment extends DataObject
}
// Check parent is available
$parent = $this->getParent();
$parent = $this->Parent();
if (!$parent || !$parent->exists()) {
return null;
}
@ -806,7 +877,7 @@ class Comment extends DataObject
// Build reply controller
$controller = CommentingController::create();
$controller->setOwnerRecord($parent);
$controller->setBaseClass($parent->ClassName);
$controller->setParentClass($parent->ClassName);
$controller->setOwnerController(Controller::curr());
return $controller->ReplyForm($this);
@ -826,115 +897,3 @@ class Comment extends DataObject
}
}
}
/**
* Provides the ability to generate cryptographically secure tokens for comment moderation
*/
class Comment_SecurityToken
{
private $secret = null;
/**
* @param Comment $comment Comment to generate this token for
*/
public function __construct($comment)
{
if (!$comment->SecretToken) {
$comment->SecretToken = $this->generate();
$comment->write();
}
$this->secret = $comment->SecretToken;
}
/**
* Generate the token for the given salt and current secret
*
* @param string $salt
*
* @return string
*/
protected function getToken($salt)
{
return hash_pbkdf2('sha256', $this->secret, $salt, 1000, 30);
}
/**
* 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.
*
* @param string $salt Single use salt
* @param Member $member Member object
*
* @return string Generated salt specific to this member
*/
protected function memberSalt($salt, $member)
{
// Fallback to salting with ID in case the member has not one set
return $salt . ($member->Salt ?: $member->ID);
}
/**
* @param string $url Comment action URL
* @param Member $member Member to restrict access to this action to
*
* @return string
*/
public function addToUrl($url, $member)
{
$salt = $this->generate(15); // New random salt; Will be passed into url
// Generate salt specific to this member
$memberSalt = $this->memberSalt($salt, $member);
$token = $this->getToken($memberSalt);
return Controller::join_links(
$url,
sprintf(
'?t=%s&s=%s',
urlencode($token),
urlencode($salt)
)
);
}
/**
* @param SS_HTTPRequest $request
*
* @return boolean
*/
public function checkRequest($request)
{
$member = Member::currentUser();
if (!$member) {
return false;
}
$salt = $request->getVar('s');
$memberSalt = $this->memberSalt($salt, $member);
$token = $this->getToken($memberSalt);
// Ensure tokens match
return $token === $request->getVar('t');
}
/**
* 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);
}
return $result;
}
}

View File

@ -0,0 +1,120 @@
<?php
namespace SilverStripe\Comments\Model\Comment;
use SilverStripe\Control\Controller;
use SilverStripe\Security\Member;
use SilverStripe\Security\RandomGenerator;
/**
* Provides the ability to generate cryptographically secure tokens for comment moderation
*/
class SecurityToken
{
/**
* @var string
*/
private $secret = null;
/**
* @param Comment $comment Comment to generate this token for
*/
public function __construct($comment)
{
if (!$comment->SecretToken) {
$comment->SecretToken = $this->generate();
$comment->write();
}
$this->secret = $comment->SecretToken;
}
/**
* Generate the token for the given salt and current secret
*
* @param string $salt
*
* @return string
*/
protected function getToken($salt)
{
return hash_pbkdf2('sha256', $this->secret, $salt, 1000, 30);
}
/**
* 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.
*
* @param string $salt Single use salt
* @param Member $member Member object
*
* @return string Generated salt specific to this member
*/
protected function memberSalt($salt, $member)
{
// Fallback to salting with ID in case the member has not one set
return $salt . ($member->Salt ?: $member->ID);
}
/**
* @param string $url Comment action URL
* @param Member $member Member to restrict access to this action to
*
* @return string
*/
public function addToUrl($url, $member)
{
$salt = $this->generate(15); // New random salt; Will be passed into url
// Generate salt specific to this member
$memberSalt = $this->memberSalt($salt, $member);
$token = $this->getToken($memberSalt);
return Controller::join_links(
$url,
sprintf(
'?t=%s&s=%s',
urlencode($token),
urlencode($salt)
)
);
}
/**
* @param SS_HTTPRequest $request
*
* @return boolean
*/
public function checkRequest($request)
{
$member = Member::currentUser();
if (!$member) {
return false;
}
$salt = $request->getVar('s');
$memberSalt = $this->memberSalt($salt, $member);
$token = $this->getToken($memberSalt);
// Ensure tokens match
return $token === $request->getVar('t');
}
/**
* 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);
}
return $result;
}
}

View File

@ -0,0 +1,46 @@
<?php
namespace SilverStripe\Comments\Tasks;
use SilverStripe\Comments\Model\Comment;
use SilverStripe\Core\Config\Config;
use SilverStripe\Dev\BuildTask;
use SilverStripe\ORM\DB;
/**
* Migrates all 3.x comment's BaseClass fields to the new ParentClass fields
*
* @package comments
*/
class MigrateCommentParentsTask extends BuildTask
{
private static $segment = 'MigrateCommentParentsTask';
protected $title = 'Migrate Comment Parent classes from 3.x';
protected $description = 'Migrates all 3.x Comment BaseClass fields to the new ParentClass fields in 4.0';
/**
* @param HTTPRequest $request
*/
public function run($request)
{
// Check if anything needs to be done
$tableName = Comment::getSchema()->tableName(Comment::class);
if (!DB::get_schema()->hasField($tableName, 'BaseClass')) {
DB::alteration_message('"BaseClass" does not exist on "' . $tableName . '", nothing to upgrade.', 'notice');
return;
}
// Set the class names to fully qualified class names first
$remapping = Config::inst()->get('SilverStripe\\ORM\\DatabaseAdmin', 'classname_value_remapping');
$updateQuery = "UPDATE \"Comment\" SET \"BaseClass\" = ? WHERE \"BaseClass\" = ?";
foreach ($remapping as $old => $new) {
DB::prepared_query($updateQuery, [$new, $old]);
}
// Move these values to ParentClass (the 4.x column name)
DB::query('UPDATE "Comment" SET "ParentClass" = "BaseClass"');
DB::alteration_message('Finished updating any applicable Comment class columns', 'notice');
}
}

View File

@ -1,23 +0,0 @@
<% if $RepliesEnabled %>
<div class="comment-replies-container">
<div class="comment-reply-form-holder">
$ReplyForm
</div>
<div class="comment-replies-holder">
<% if $Replies %>
<ul class="comments-list level-{$Depth}">
<% loop $Replies %>
<li class="comment $EvenOdd<% if FirstLast %> $FirstLast <% end_if %> $SpamClass">
<% include CommentsInterface_singlecomment %>
</li>
<% end_loop %>
</ul>
<% with $Replies %>
<% include ReplyPagination %>
<% end_with %>
<% end_if %>
</div>
</div>
<% end_if %>

View File

@ -11,7 +11,7 @@
<% end_if %>
$AddCommentForm
<% else %>
<p><% _t('CommentsInterface_ss.COMMENTLOGINERROR', 'You cannot post comments until you have logged in') %><% if $PostingRequiredPermission %>,<% _t('CommentsInterface_ss.COMMENTPERMISSIONERROR', 'and that you have an appropriate permission level') %><% end_if %>.
<p><% _t('CommentsInterface_ss.COMMENTLOGINERROR', 'You cannot post comments until you have logged in') %><% if $PostingRequiredPermission %>, <% _t('CommentsInterface_ss.COMMENTPERMISSIONERROR', 'and have an appropriate permission level') %><% end_if %>.
<a href="Security/login?BackURL={$Parent.Link}" title="<% _t('CommentsInterface_ss.LOGINTOPOSTCOMMENT', 'Login to post a comment') %>"><% _t('CommentsInterface_ss.COMMENTPOSTLOGIN', 'Login Here') %></a>.
</p>
<% end_if %>

View File

@ -0,0 +1,25 @@
<% if $RepliesEnabled %>
<div class="comment-replies-container">
<% if $canPostComment %>
<div class="comment-reply-form-holder">
$ReplyForm
</div>
<% end_if %>
<div class="comment-replies-holder">
<% if $Replies %>
<ul class="comments-list level-{$Depth}">
<% loop $Replies %>
<li class="comment $EvenOdd<% if FirstLast %> $FirstLast <% end_if %> $SpamClass">
<% include CommentsInterface_singlecomment %>
</li>
<% end_loop %>
</ul>
<% with $Replies %>
<% include ReplyPagination %>
<% end_with %>
<% end_if %>
</div>
</div>
<% end_if %>

View File

@ -32,7 +32,7 @@
<a href="$DeleteLink.ATT" class="delete"><% _t('CommentsInterface_singlecomment_ss.REMCOM','reject it') %></a>
<% end_if %>
</div>
<% if $RepliesEnabled %>
<% if $RepliesEnabled && $canPostComment %>
<a class="comment-reply-link" href="#{$ReplyForm.FormName}"><% _t('CommentsInterface_singlecomment_ss.REPLYTO','Reply to') %> $AuthorName.XML</a>
<% end_if %>
</div>

View File

@ -1,10 +1,19 @@
<?php
namespace SilverStripe\Comments\Tests;
use SilverStripe\Comments\Admin\CommentAdmin;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\i18n\i18n;
use SilverStripe\Security\Member;
class CommentAdminTest extends SapphireTest
{
/**
* {@inheritDoc}
*/
protected $usesDatabase = true;
public function testProvidePermissions()
{
$commentAdmin = new CommentAdmin();

View File

@ -1,145 +0,0 @@
<?php
class CommentListTest extends FunctionalTest
{
public static $fixture_file = 'comments/tests/CommentsTest.yml';
protected $extraDataObjects = array(
'CommentableItem',
'CommentableItemEnabled',
'CommentableItemDisabled'
);
public function setUp()
{
parent::setUp();
Config::nest();
// Set good default values
Config::inst()->update('CommentsExtension', 'comments', array(
'enabled' => true,
'enabled_cms' => false,
'require_login' => false,
'require_login_cms' => false,
'required_permission' => false,
'require_moderation_nonmembers' => false,
'require_moderation' => false,
'require_moderation_cms' => false,
'frontend_moderation' => false,
'frontend_spam' => false,
));
// Configure this dataobject
Config::inst()->update('CommentableItem', 'comments', array(
'enabled_cms' => true
));
}
public function tearDown()
{
Config::unnest();
parent::tearDown();
}
public function testGetForeignClass()
{
$item = $this->objFromFixture('CommentableItem', 'first');
// This is the class the Comments are related to
$this->assertEquals('CommentableItem',
$item->Comments()->getForeignClass());
}
public function testAddNonComment()
{
$item = $this->objFromFixture('CommentableItem', 'first');
$comments = $item->Comments();
$this->assertEquals(4, $comments->count());
$member = Member::get()->first();
try {
$comments->add($member);
$this->fail('Should not have been able to add member to comments');
} catch (InvalidArgumentException $e) {
$this->assertEquals(
'CommentList::add() expecting a Comment object, or ID value',
$e->getMessage()
);
}
}
public function testAddComment()
{
$item = $this->objFromFixture('CommentableItem', 'first');
$firstComment = $this->objFromFixture('Comment', 'firstComA');
$comments = $item->Comments();//->sort('Created');
foreach ($comments as $comment) {
error_log($comment->ID . ' ' . $comment->Created .' ' . $comment->Comment);
}
$this->assertEquals(4, $comments->count());
$newComment = new Comment();
$newComment->Name = 'Fred Bloggs';
$newComment->Comment = 'This is a test comment';
$newComment->write();
$comments->add($newComment);
// As a comment has been added, there should be 5 comments now
$this->assertEquals(5, $item->Comments()->count());
$newComment2 = new Comment();
$newComment2->Name = 'John Smith';
$newComment2->Comment = 'This is another test comment';
$newComment2->write();
// test adding the same comment by ID
$comments->add($newComment2->ID);
$this->assertEquals(6, $item->Comments()->count());
$this->setExpectedException(
'InvalidArgumentException',
"CommentList::add() can't be called until a single foreign ID is set"
);
$list = new CommentList('CommentableItem');
$list->add($newComment);
}
public function testRemoveComment()
{
// remove by comment
$item = $this->objFromFixture('CommentableItem', 'first');
$this->assertEquals(4, $item->Comments()->count());
$comments = $item->Comments();
$comment = $comments->first();
$comments->remove($comment);
// now remove by ID
$comments = $item->Comments();
$comment = $comments->first();
$comments->remove($comment->ID);
$this->assertEquals(2, $item->Comments()->count());
}
public function testRemoveNonComment()
{
$item = $this->objFromFixture('CommentableItem', 'first');
$this->assertEquals(4, $item->Comments()->count());
$comments = $item->Comments();
// try and remove a non comment
$member = Member::get()->first();
try {
$comments->remove($member);
$this->fail('Should not have been able to remove member from comments');
} catch (InvalidArgumentException $e) {
$this->assertEquals(
'CommentList::remove() expecting a Comment object, or ID',
$e->getMessage()
);
}
}
}

View File

@ -1,27 +1,28 @@
<?php
class CommentTestHelper
namespace SilverStripe\Comments\Tests;
use SilverStripe\Dev\TestOnly;
use SilverStripe\Forms\FieldGroup;
class CommentTestHelper implements TestOnly
{
/*
This only works if the last section is not a field group, e.g. a Comments
field group inside of a Root.Settings tab will not work
/**
* This only works if the last section is not a field group, e.g. a Comments
* field group inside of a Root.Settings tab will not work
*/
public static function assertFieldsForTab($context, $tabName, $expected, $fields)
{
$tab = $fields->findOrMakeTab($tabName);
$fields = $tab->FieldList();
CommentTestHelper::assertFieldNames($context, $expected, $fields);
self::assertFieldNames($context, $expected, $fields);
}
public static function assertFieldNames($context, $expected, $fields)
{
$actual = array();
foreach ($fields as $field) {
if (get_class($field) == 'FieldGroup') {
array_push($actual, $field->Name());
} else {
array_push($actual, $field->getName());
}
array_push($actual, $field->getName());
}
$context->assertEquals($expected, $actual);
}

View File

@ -1,16 +1,36 @@
<?php
namespace SilverStripe\Comments\Tests;
use SilverStripe\Comments\Controllers\CommentingController;
use SilverStripe\Comments\Model\Comment;
use SilverStripe\Comments\Model\Comment\SecurityToken as CommentSecurityToken;
use SilverStripe\Comments\Tests\Stubs\CommentableItem;
use SilverStripe\Comments\Tests\CommentTestHelper;
use SilverStripe\Control\Controller;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Email\Email;
use SilverStripe\Dev\FunctionalTest;
use SilverStripe\ORM\DataObject;
use SilverStripe\Security\Member;
use SilverStripe\Security\SecurityToken;
/**
* @package comments
* @subpackage tests
*/
class CommentingControllerTest extends FunctionalTest
{
/**
* {@inheritDoc}
*/
public static $fixture_file = 'CommentsTest.yml';
/**
* {@inheritDoc}
*/
protected $extraDataObjects = array(
'CommentableItem'
CommentableItem::class
);
protected $securityEnabled;
@ -18,9 +38,9 @@ class CommentingControllerTest extends FunctionalTest
public function tearDown()
{
if ($this->securityEnabled) {
SecurityToken::enable();
SecurityToken::inst()->enable();
} else {
SecurityToken::disable();
SecurityToken::inst()->disable();
}
parent::tearDown();
}
@ -28,30 +48,32 @@ class CommentingControllerTest extends FunctionalTest
public function setUp()
{
parent::setUp();
$this->securityEnabled = SecurityToken::is_enabled();
$this->securityEnabled = SecurityToken::inst()->is_enabled();
// We will assert against explicit responses, unless handed otherwise in a test for redirects
$this->autoFollowRedirection = false;
}
public function testApprove()
public function testApproveUnmoderatedComment()
{
SecurityToken::disable();
SecurityToken::inst()->disable();
// mark a comment as spam then approve it
$this->logInWithPermission('CMS_ACCESS_CommentAdmin');
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment->markSpam();
$st = new Comment_SecurityToken($comment);
$url = 'CommentingController/approve/' . $comment->ID;
$comment = $this->objFromFixture(Comment::class, 'testModeratedComment1');
$st = new CommentSecurityToken($comment);
$url = 'comments/approve/' . $comment->ID;
$url = $st->addToUrl($url, Member::currentUser());
$response = $this->get($url);
$this->assertEquals(200, $response->getStatusCode());
$comment = DataObject::get_by_id('Comment', $comment->ID);
$response = $this->get($url, null, ['Referer' => '/']);
$this->assertEquals(302, $response->getStatusCode());
$comment = DataObject::get_by_id(Comment::class, $comment->ID);
// Need to use 0,1 here instead of false, true for SQLite
$this->assertEquals(0, $comment->IsSpam);
$this->assertEquals(1, $comment->Moderated);
// try and approve a non existent comment
$response = $this->get('CommentingController/approve/100000');
$response = $this->get('comments/approve/100000');
$this->assertEquals(404, $response->getStatusCode());
}
@ -66,25 +88,25 @@ class CommentingControllerTest extends FunctionalTest
public function testHam()
{
SecurityToken::disable();
SecurityToken::inst()->disable();
// mark a comment as spam then ham it
$this->logInWithPermission('CMS_ACCESS_CommentAdmin');
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$comment->markSpam();
$st = new Comment_SecurityToken($comment);
$url = 'CommentingController/ham/' . $comment->ID;
$st = new CommentSecurityToken($comment);
$url = 'comments/ham/' . $comment->ID;
$url = $st->addToUrl($url, Member::currentUser());
$response = $this->get($url);
$this->assertEquals(200, $response->getStatusCode());
$comment = DataObject::get_by_id('Comment', $comment->ID);
$this->assertEquals(302, $response->getStatusCode());
$comment = DataObject::get_by_id(Comment::class, $comment->ID);
// Need to use 0,1 here instead of false, true for SQLite
$this->assertEquals(0, $comment->IsSpam);
$this->assertEquals(1, $comment->Moderated);
// try and ham a non existent comment
$response = $this->get('CommentingController/ham/100000');
$response = $this->get('comments/ham/100000');
$this->assertEquals(404, $response->getStatusCode());
}
@ -92,55 +114,54 @@ class CommentingControllerTest extends FunctionalTest
{
// mark a comment as approved then spam it
$this->logInWithPermission('CMS_ACCESS_CommentAdmin');
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$comment->markApproved();
$st = new Comment_SecurityToken($comment);
$url = 'CommentingController/spam/' . $comment->ID;
$st = new CommentSecurityToken($comment);
$url = 'comments/spam/' . $comment->ID;
$url = $st->addToUrl($url, Member::currentUser());
$response = $this->get($url);
$this->assertEquals(200, $response->getStatusCode());
$comment = DataObject::get_by_id('Comment', $comment->ID);
$this->assertEquals(302, $response->getStatusCode());
$comment = DataObject::get_by_id(Comment::class, $comment->ID);
// Need to use 0,1 here instead of false, true for SQLite
$this->assertEquals(1, $comment->IsSpam);
$this->assertEquals(1, $comment->Moderated);
// try and spam a non existent comment
$response = $this->get('CommentingController/spam/100000');
$response = $this->get('comments/spam/100000');
$this->assertEquals(404, $response->getStatusCode());
}
public function testRSS()
{
// Delete the newly added children of firstComA so as not to have to recalculate values below
$this->objFromFixture('Comment', 'firstComAChild1')->delete();
$this->objFromFixture('Comment', 'firstComAChild2')->delete();
$this->objFromFixture('Comment', 'firstComAChild3')->delete();
$item = $this->objFromFixture('CommentableItem', 'first');
$this->objFromFixture(Comment::class, 'firstComAChild1')->delete();
$this->objFromFixture(Comment::class, 'firstComAChild2')->delete();
$this->objFromFixture(Comment::class, 'firstComAChild3')->delete();
$item = $this->objFromFixture(CommentableItem::class, 'first');
// comments sitewide
$response = $this->get('CommentingController/rss');
$response = $this->get('comments/rss');
$this->assertEquals(10, substr_count($response->getBody(), "<item>"), "10 approved, non spam comments on page 1");
$response = $this->get('CommentingController/rss?start=10');
$response = $this->get('comments/rss?start=10');
$this->assertEquals(4, substr_count($response->getBody(), "<item>"), "3 approved, non spam comments on page 2");
// all comments on a type
$response = $this->get('CommentingController/rss/CommentableItem');
$response = $this->get('comments/rss/SilverStripe-Comments-Tests-Stubs-CommentableItem');
$this->assertEquals(10, substr_count($response->getBody(), "<item>"));
$response = $this->get('CommentingController/rss/CommentableItem?start=10');
$response = $this->get('comments/rss/SilverStripe-Comments-Tests-Stubs-CommentableItem?start=10');
$this->assertEquals(4, substr_count($response->getBody(), "<item>"), "3 approved, non spam comments on page 2");
// specific page
$response = $this->get('CommentingController/rss/CommentableItem/'.$item->ID);
$response = $this->get('comments/rss/SilverStripe-Comments-Tests-Stubs-CommentableItem/'.$item->ID);
$this->assertEquals(1, substr_count($response->getBody(), "<item>"));
$this->assertContains('<dc:creator>FA</dc:creator>', $response->getBody());
// test accessing comments on a type that doesn't exist
$response = $this->get('CommentingController/rss/Fake');
$response = $this->get('comments/rss/Fake');
$this->assertEquals(404, $response->getStatusCode());
}
@ -151,8 +172,8 @@ class CommentingControllerTest extends FunctionalTest
$comment = $this->objFromFixture('Comment', 'firstComA');
$item = $this->objFromFixture('CommentableItem', 'first');
$st = new Comment_SecurityToken($comment);
$url = 'CommentingController/reply/' . $item->ID.'?ParentCommentID=' . $comment->ID;
$st = new CommentSecurityToken($comment);
$url = 'comments/reply/' . $item->ID.'?ParentCommentID=' . $comment->ID;
error_log($url);
$response = $this->get($url);
error_log(print_r($response,1));
@ -167,7 +188,7 @@ class CommentingControllerTest extends FunctionalTest
'use_preview' => false
));
$this->logInAs('visitor');
SecurityToken::disable();
SecurityToken::inst()->disable();
$parent = $this->objFromFixture('CommentableItem', 'first');
$parent->CommentsRequireLogin = true;
$parent->PostingRequiredPermission = true;
@ -185,17 +206,17 @@ class CommentingControllerTest extends FunctionalTest
public function testCommentsFormUsePreview()
{
// test with preview on
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'use_preview' => true
));
$this->objFromFixture('Comment', 'firstComAChild1')->delete();
$this->objFromFixture('Comment', 'firstComAChild2')->delete();
$this->objFromFixture('Comment', 'firstComAChild3')->delete();
$this->objFromFixture(Comment::class, 'firstComAChild1')->delete();
$this->objFromFixture(Comment::class, 'firstComAChild2')->delete();
$this->objFromFixture(Comment::class, 'firstComAChild3')->delete();
SecurityToken::disable();
SecurityToken::inst()->disable();
$this->autoFollowRedirection = false;
$parent = $this->objFromFixture('CommentableItem', 'first');
$parent = $this->objFromFixture(CommentableItem::class, 'first');
$commController = new CommentingController();
$commController->setOwnerRecord($parent);
@ -205,7 +226,7 @@ class CommentingControllerTest extends FunctionalTest
CommentTestHelper::assertFieldNames($this, $expected, $commentsFields);
// Turn off preview. Assert lack of preview field
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'use_preview' => false
));
$form = $commController->CommentsForm();
@ -216,64 +237,89 @@ class CommentingControllerTest extends FunctionalTest
public function testCommentsForm()
{
// Delete the newly added children of firstComA so as not to change this test
$this->objFromFixture('Comment', 'firstComAChild1')->delete();
$this->objFromFixture('Comment', 'firstComAChild2')->delete();
$this->objFromFixture('Comment', 'firstComAChild3')->delete();
$this->autoFollowRedirection = true;
SecurityToken::disable();
// Delete the newly added children of firstComA so as not to change this test
$this->objFromFixture(Comment::class, 'firstComAChild1')->delete();
$this->objFromFixture(Comment::class, 'firstComAChild2')->delete();
$this->objFromFixture(Comment::class, 'firstComAChild3')->delete();
SecurityToken::inst()->disable();
$this->autoFollowRedirection = false;
$parent = $this->objFromFixture('CommentableItem', 'first');
$parent = $this->objFromFixture(CommentableItem::class, 'first');
// Test posting to base comment
$response = $this->post('CommentingController/CommentsForm',
$response = $this->post(
'comments/CommentsForm',
array(
'Name' => 'Poster',
'Email' => 'guy@test.com',
'Comment' => 'My Comment',
'ParentID' => $parent->ID,
'BaseClass' => 'CommentableItem',
'ParentClassName' => CommentableItem::class,
'action_doPostComment' => 'Post'
)
);
$this->assertEquals(302, $response->getStatusCode());
$this->assertStringStartsWith('CommentableItem_Controller#comment-', $response->getHeader('Location'));
// $this->assertStringStartsWith('CommentableItemController#comment-', $response->getHeader('Location'));
$this->assertDOSEquals(
array(array(
'Name' => 'Poster',
'Email' => 'guy@test.com',
'Comment' => 'My Comment',
'ParentID' => $parent->ID,
'BaseClass' => 'CommentableItem',
)),
array(
array(
'Name' => 'Poster',
'Email' => 'guy@test.com',
'Comment' => 'My Comment',
'ParentID' => $parent->ID,
'ParentClass' => CommentableItem::class,
)
),
Comment::get()->filter('Email', 'guy@test.com')
);
// Test posting to parent comment
$parentComment = $this->objFromFixture('Comment', 'firstComA');
$parentComment = $this->objFromFixture(Comment::class, 'firstComA');
$this->assertEquals(0, $parentComment->ChildComments()->count());
$response = $this->post(
'CommentingController/reply/'.$parentComment->ID,
'comments/reply/' . $parentComment->ID,
array(
'Name' => 'Test Author',
'Email' => 'test@test.com',
'Comment' => 'Making a reply to firstComA',
'ParentID' => $parent->ID,
'BaseClass' => 'CommentableItem',
'ParentClassName' => CommentableItem::class,
'ParentCommentID' => $parentComment->ID,
'action_doPostComment' => 'Post'
)
);
$this->assertEquals(302, $response->getStatusCode());
$this->assertStringStartsWith('CommentableItem_Controller#comment-', $response->getHeader('Location'));
$this->assertDOSEquals(array(array(
'Name' => 'Test Author',
'Email' => 'test@test.com',
'Comment' => 'Making a reply to firstComA',
'ParentID' => $parent->ID,
'BaseClass' => 'CommentableItem',
'ParentCommentID' => $parentComment->ID
)), $parentComment->ChildComments());
// $this->assertStringStartsWith('CommentableItemController#comment-', $response->getHeader('Location'));
$this->assertDOSEquals(
array(
array(
'Name' => 'Test Author',
'Email' => 'test@test.com',
'Comment' => 'Making a reply to firstComA',
'ParentID' => $parent->ID,
'ParentClass' => CommentableItem::class,
'ParentCommentID' => $parentComment->ID
)
),
$parentComment->ChildComments()
);
}
/**
* SS4 introduces namespaces. They don't work in URLs, so we encode and decode them here.
*/
public function testEncodeClassName()
{
$controller = new CommentingController;
$this->assertSame('SilverStripe-Comments-Model-Comment', $controller->encodeClassName(Comment::class));
}
public function testDecodeClassName()
{
$controller = new CommentingController;
$this->assertSame(Comment::class, $controller->decodeClassName('SilverStripe-Comments-Model-Comment'));
}
}

View File

@ -1,180 +0,0 @@
<?php
class CommentingTest extends SapphireTest
{
public function setUpOnce()
{
parent::setUpOnce();
}
public function testDeprecatedMethods()
{
$methods = array('add', 'remove', 'has_commenting');
foreach ($methods as $methodName) {
try {
Commenting::$methodName('Member');
} catch (PHPUnit_Framework_Error_Deprecated $e) {
$expected = 'Using Commenting:' . $methodName .' is deprecated.'
. ' Please use the config API instead';
$this->assertEquals($expected, $e->getMessage());
}
}
}
public function test_set_config_value()
{
// public static function set_config_value($class, $key, $value = false) {
Commenting::set_config_value(
'CommentableItem',
'comments_holder_id',
'commentable_item'
);
$config = Config::inst()->get(
'CommentableItem',
'comments'
);
$actual = $config['comments_holder_id'];
$this->assertEquals(
'commentable_item',
$actual
);
Commenting::set_config_value(
'all',
'comments_holder_id',
'all_items_actually_commentsextension'
);
$config = Config::inst()->get(
'CommentsExtension',
'comments'
);
$actual = $config['comments_holder_id'];
$this->assertEquals(
'all_items_actually_commentsextension',
$actual
);
}
public function test_get_config_value()
{
Config::inst()->update('CommentableItem', 'comments',
array(
'comments_holder_id' => 'commentable_item'
)
);
$this->assertEquals(
'commentable_item',
Commenting::get_config_value('CommentableItem', 'comments_holder_id')
);
Config::inst()->update('CommentsExtension', 'comments',
array(
'comments_holder_id' => 'comments_extension'
)
);
// if class is null, method uses the CommentsExtension property
$this->assertEquals(
'comments_extension',
Commenting::get_config_value(null, 'comments_holder_id')
);
$this->setExpectedException(
'InvalidArgumentException',
'Member does not have commenting enabled'
);
Commenting::get_config_value('Member', 'comments_holder_id');
}
public function test_config_value_equals()
{
Config::inst()->update('CommentableItem', 'comments',
array(
'comments_holder_id' => 'some_value'
)
);
$this->assertTrue(
Commenting::config_value_equals(
'CommentableItem',
'comments_holder_id',
'some_value'
)
);
$this->assertNull(
Commenting::config_value_equals(
'CommentableItem',
'comments_holder_id',
'not_some_value'
)
);
}
public function test_add()
{
Commenting::add('Member', array('comments_holder_id' => 'test_add_value'));
$config = Config::inst()->get(
'Member',
'comments'
);
$actual = $config['comments_holder_id'];
$this->assertEquals(
'test_add_value',
$actual
);
Commenting::add('Member');
$config = Config::inst()->get(
'Member',
'comments'
);
$actual = $config['comments_holder_id'];
// no settings updated
$this->assertEquals(
'test_add_value',
$actual
);
$this->setExpectedException('InvalidArgumentException', "\$settings needs to be an array or null");
Commenting::add('Member', 'illegal format, not an array');
}
public function test_can_member_post()
{
// logout
if ($member = Member::currentUser()) {
$member->logOut();
}
Config::inst()->update('CommentableItem', 'comments',
array(
'require_login' => false
)
);
$this->assertTrue(Commenting::can_member_post('CommentableItem'));
Config::inst()->update('CommentableItem', 'comments',
array(
'require_login' => true
)
);
$this->assertFalse(Commenting::can_member_post('CommentableItem'));
$this->logInWithPermission('CMS_ACCESS_CommentAdmin');
$this->assertTrue(Commenting::can_member_post('CommentableItem'));
Config::inst()->update('CommentableItem', 'comments',
array(
'require_login' => false
)
);
$this->assertTrue(Commenting::can_member_post('CommentableItem'));
}
}

View File

@ -1,14 +1,32 @@
<?php
namespace SilverStripe\Comments\Tests;
use SilverStripe\Comments\Extensions\CommentsExtension;
use SilverStripe\Comments\Model\Comment;
use SilverStripe\Comments\Tests\CommentTestHelper;
use SilverStripe\Comments\Tests\Stubs\CommentableItem;
use SilverStripe\Comments\Tests\Stubs\CommentableItemDisabled;
use SilverStripe\Comments\Tests\Stubs\CommentableItemEnabled;
use SilverStripe\Core\Config\Config;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Security\Member;
use SilverStripe\View\Requirements;
class CommentsExtensionTest extends SapphireTest
{
/**
* {@inheritDoc}
*/
public static $fixture_file = 'comments/tests/CommentsTest.yml';
/**
* {@inheritDoc}
*/
protected $extraDataObjects = array(
'CommentableItem',
'CommentableItemEnabled',
'CommentableItemDisabled'
CommentableItem::class,
CommentableItemEnabled::class,
CommentableItemDisabled::class
);
public function setUp()
@ -17,7 +35,7 @@ class CommentsExtensionTest extends SapphireTest
Config::nest();
// Set good default values
Config::inst()->update('CommentsExtension', 'comments', array(
Config::inst()->update(CommentsExtension::class, 'comments', array(
'enabled' => true,
'enabled_cms' => false,
'require_login' => false,
@ -31,11 +49,11 @@ class CommentsExtensionTest extends SapphireTest
));
$this->requiredExtensions = array(
'CommentableItem' => 'CommentsExtension'
'CommentableItem' => CommentsExtension::class
);
// Configure this dataobject
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'enabled_cms' => true
));
}
@ -60,7 +78,7 @@ class CommentsExtensionTest extends SapphireTest
{
// the 3 options take precedence in this order, executed if true
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'require_moderation_cms' => true,
'require_moderation' => true,
'require_moderation_nonmembers' => true
@ -68,7 +86,7 @@ class CommentsExtensionTest extends SapphireTest
// With require moderation CMS set to true, the value of the field
// 'ModerationRequired' is returned
$item = $this->objFromFixture('CommentableItem', 'first');
$item = $this->objFromFixture(CommentableItem::class, 'first');
$item->ModerationRequired = 'None';
$this->assertEquals('None', $item->getModerationRequired());
$item->ModerationRequired = 'Required';
@ -76,21 +94,21 @@ class CommentsExtensionTest extends SapphireTest
$item->ModerationRequired = 'NonMembersOnly';
$this->assertEquals('NonMembersOnly', $item->getModerationRequired());
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'require_moderation_cms' => false,
'require_moderation' => true,
'require_moderation_nonmembers' => true
));
$this->assertEquals('Required', $item->getModerationRequired());
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'require_moderation_cms' => false,
'require_moderation' => false,
'require_moderation_nonmembers' => true
));
$this->assertEquals('NonMembersOnly', $item->getModerationRequired());
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'require_moderation_cms' => false,
'require_moderation' => false,
'require_moderation_nonmembers' => false
@ -100,24 +118,24 @@ class CommentsExtensionTest extends SapphireTest
public function testGetCommentsRequireLogin()
{
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'require_login_cms' => true
));
// With require moderation CMS set to true, the value of the field
// 'ModerationRequired' is returned
$item = $this->objFromFixture('CommentableItem', 'first');
$item = $this->objFromFixture(CommentableItem::class, 'first');
$item->CommentsRequireLogin = true;
$this->assertTrue($item->getCommentsRequireLogin());
$item->CommentsRequireLogin = false;
$this->assertFalse($item->getCommentsRequireLogin());
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'require_login_cms' => false,
'require_login' => false
));
$this->assertFalse($item->getCommentsRequireLogin());
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'require_login_cms' => false,
'require_login' => true
));
@ -146,13 +164,13 @@ class CommentsExtensionTest extends SapphireTest
public function testGetCommentHolderID()
{
$item = $this->objFromFixture('CommentableItem', 'first');
Config::inst()->update('CommentableItem', 'comments', array(
$item = $this->objFromFixture(CommentableItem::class, 'first');
Config::inst()->update(CommentableItem::class, 'comments', array(
'comments_holder_id' => 'commentid_test1',
));
$this->assertEquals('commentid_test1', $item->getCommentHolderID());
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'comments_holder_id' => 'commtentid_test_another',
));
$this->assertEquals('commtentid_test_another', $item->getCommentHolderID());
@ -171,7 +189,7 @@ class CommentsExtensionTest extends SapphireTest
Member::currentUser()->logOut();
}
$item = $this->objFromFixture('CommentableItem', 'first');
$item = $this->objFromFixture(CommentableItem::class, 'first');
$this->assertFalse($item->canModerateComments());
$this->logInWithPermission('CMS_ACCESS_CommentAdmin');
@ -180,33 +198,39 @@ class CommentsExtensionTest extends SapphireTest
public function testGetCommentRSSLink()
{
$item = $this->objFromFixture('CommentableItem', 'first');
$link = $item->getCommentRSSLink();
$this->assertEquals('/CommentingController/rss', $link);
}
Config::inst()->update('SilverStripe\\Control\\Director', 'alternate_base_url', 'http://unittesting.local');
$item = $this->objFromFixture(CommentableItem::class, 'first');
$link = $item->getCommentRSSLink();
$this->assertEquals('http://unittesting.local/comments/rss', $link);
}
public function testGetCommentRSSLinkPage()
{
$item = $this->objFromFixture('CommentableItem', 'first');
Config::inst()->update('SilverStripe\\Control\\Director', 'alternate_base_url', 'http://unittesting.local');
$item = $this->objFromFixture(CommentableItem::class, 'first');
$page = $item->getCommentRSSLinkPage();
$this->assertEquals(
'/CommentingController/rss/CommentableItem/' . $item->ID,
'http://unittesting.local/comments/rss/SilverStripe-Comments-Tests-Stubs-CommentableItem/' . $item->ID,
$page
);
}
public function testCommentsForm()
{
Config::inst()->update('CommentableItem', 'comments', array(
'include_js' => false
Config::inst()->update(
CommentableItem::class,
'comments',
array(
'include_js' => false
)
);
$item = $this->objFromFixture('CommentableItem', 'first');
$item = $this->objFromFixture(CommentableItem::class, 'first');
// The comments form is HTML to do assertions by contains
$cf = $item->CommentsForm();
$expected = '<form id="Form_CommentsForm" action="/CommentingController'
$expected = '<form id="Form_CommentsForm" action="/comments'
. '/CommentsForm" method="post" enctype="application/x-www-form-urlenco'
. 'ded">';
$this->assertContains($expected, $cf);
@ -231,13 +255,13 @@ class CommentsExtensionTest extends SapphireTest
$expected = '<input type="submit" name="action_doPostComment" value="Post" class="action" id="Form_CommentsForm_action_doPostComment"';
$this->assertContains($expected, $cf);
$expected = '<a href="/CommentingController/spam/';
$expected = '<a href="/comments/spam/';
$this->assertContains($expected, $cf);
$expected = '<p>Reply to firstComA 1</p>';
$this->assertContains($expected, $cf);
$expected = '<a href="/CommentingController/delete';
$expected = '<a href="/comments/delete';
$this->assertContains($expected, $cf);
$expected = '<p>Reply to firstComA 2</p>';
@ -250,28 +274,36 @@ class CommentsExtensionTest extends SapphireTest
$backend = Requirements::backend();
$this->assertEquals(
array(),
$backend->get_javascript()
$backend->getJavascript()
);
Config::inst()->update('CommentableItem', 'comments', array(
'include_js' => true
Config::inst()->update(
CommentableItem::class,
'comments',
array(
'include_js' => true
)
);
$cf = $item->CommentsForm();
$backend = Requirements::backend();
$this->assertEquals(
array(
'framework/thirdparty/jquery/jquery.js',
'framework/thirdparty/jquery-entwine/dist/jquery.entwine-dist.js',
'framework/thirdparty/jquery-validate/lib/jquery.form.js',
'comments/thirdparty/jquery-validate/jquery.validate.min.js',
'framework/javascript/i18n.js',
'comments/javascript/lang/en.js',
'comments/javascript/CommentsInterface.js'
),
$backend->get_javascript()
$javascriptRequirements = $backend->getJavascript();
$expected = array(
'framework/admin/thirdparty/jquery/jquery.js',
'framework/admin/thirdparty/jquery-entwine/dist/jquery.entwine-dist.js',
'framework/admin/thirdparty/jquery-form/jquery.form.js',
'comments/thirdparty/jquery-validate/jquery.validate.min.js',
/**
* @todo: Is there a replacement for this? The docs are unclear
*/
// 'framework/admin/client/src/i18n.js',
'comments/javascript/lang/en.js',
'comments/javascript/CommentsInterface.js'
);
foreach ($expected as $javascript) {
$this->assertArrayHasKey($javascript, $javascriptRequirements);
};
}
public function testAttachedToSiteTree()
@ -281,7 +313,7 @@ class CommentsExtensionTest extends SapphireTest
public function testPagedComments()
{
$item = $this->objFromFixture('CommentableItem', 'first');
$item = $this->objFromFixture(CommentableItem::class, 'first');
// Ensure Created times are set, as order not guaranteed if all set to 0
$comments = $item->PagedComments()->sort('ID');
$ctr = 0;
@ -299,19 +331,19 @@ class CommentsExtensionTest extends SapphireTest
}
$this->assertEquals(
$this->objFromFixture('Comment', 'firstComA')->Comment,
$this->objFromFixture(Comment::class, 'firstComA')->Comment,
$results[3]->Comment
);
$this->assertEquals(
$this->objFromFixture('Comment', 'firstComAChild1')->Comment,
$this->objFromFixture(Comment::class, 'firstComAChild1')->Comment,
$results[2]->Comment
);
$this->assertEquals(
$this->objFromFixture('Comment', 'firstComAChild2')->Comment,
$this->objFromFixture(Comment::class, 'firstComAChild2')->Comment,
$results[1]->Comment
);
$this->assertEquals(
$this->objFromFixture('Comment', 'firstComAChild3')->Comment,
$this->objFromFixture(Comment::class, 'firstComAChild3')->Comment,
$results[0]->Comment
);
@ -330,37 +362,51 @@ class CommentsExtensionTest extends SapphireTest
public function testUpdateCMSFields()
{
Config::inst()->update('CommentableItem', 'comments', array(
'require_login_cms' => false
Config::inst()->update(
CommentableItem::class,
'comments',
array(
'require_login_cms' => false
)
);
$this->logInWithPermission('ADMIN');
$item = $this->objFromFixture('CommentableItem', 'first');
$item = $this->objFromFixture(CommentableItem::class, 'first');
$item->ProvideComments = true;
$item->write();
$fields = $item->getCMSFields();
CommentTestHelper::assertFieldsForTab($this, 'Root.Comments',
CommentTestHelper::assertFieldsForTab(
$this,
'Root.Comments',
array('CommentsNewCommentsTab', 'CommentsCommentsTab', 'CommentsSpamCommentsTab'),
$fields
);
CommentTestHelper::assertFieldsForTab($this, 'Root.Comments.CommentsNewCommentsTab',
CommentTestHelper::assertFieldsForTab(
$this,
'Root.Comments.CommentsNewCommentsTab',
array('NewComments'),
$fields
);
CommentTestHelper::assertFieldsForTab($this, 'Root.Comments.CommentsCommentsTab',
CommentTestHelper::assertFieldsForTab(
$this,
'Root.Comments.CommentsCommentsTab',
array('ApprovedComments'),
$fields
);
CommentTestHelper::assertFieldsForTab($this, 'Root.Comments.CommentsSpamCommentsTab',
CommentTestHelper::assertFieldsForTab(
$this,
'Root.Comments.CommentsSpamCommentsTab',
array('SpamComments'),
$fields
);
Config::inst()->update('CommentableItem', 'comments', array(
'require_login_cms' => true
Config::inst()->update(
CommentableItem::class,
'comments',
array(
'require_login_cms' => true
)
);
$fields = $item->getCMSFields();
@ -376,9 +422,12 @@ class CommentsExtensionTest extends SapphireTest
$fields
);
Config::inst()->update('CommentableItem', 'comments', array(
'require_login_cms' => true,
'require_moderation_cms' => true
Config::inst()->update(
CommentableItem::class,
'comments',
array(
'require_login_cms' => true,
'require_moderation_cms' => true
)
);
@ -386,7 +435,8 @@ class CommentsExtensionTest extends SapphireTest
CommentTestHelper::assertFieldsForTab(
$this,
'Root.Settings',
array('Comments', 'ModerationRequired'), $fields
array('Comments', 'ModerationRequired'),
$fields
);
$settingsTab = $fields->findOrMakeTab('Root.Settings');
$settingsChildren = $settingsTab->getChildren();
@ -399,32 +449,4 @@ class CommentsExtensionTest extends SapphireTest
$fields
);
}
public function testDeprecatedMethods()
{
$item = $this->objFromFixture('CommentableItem', 'first');
$methodNames = array(
'getRssLinkPage',
'getRssLink',
'PageComments',
'getPostingRequiresPermission',
'canPost',
'getCommentsConfigured'
);
foreach ($methodNames as $methodName) {
try {
$item->$methodName();
$this->fail('Method ' . $methodName .' should be depracated');
} catch (PHPUnit_Framework_Error_Deprecated $e) {
$expected = 'CommentsExtension->' . $methodName . ' is '.
'deprecated.';
$this->assertStringStartsWith($expected, $e->getMessage());
}
}
// ooh, $this->setExpectedException('ExpectedException', 'Expected Message');
}
}

View File

@ -1,8 +1,22 @@
<?php
namespace SilverStripe\Comments\Tests;
use SilverStripe\Comments\Admin\CommentsGridField;
use SilverStripe\Comments\Admin\CommentsGridFieldAction;
use SilverStripe\Comments\Admin\CommentsGridFieldConfig;
use SilverStripe\Comments\Model\Comment;
use SilverStripe\Control\Controller;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Form;
use SilverStripe\Forms\GridField\GridFieldDeleteAction;
use SilverStripe\Forms\Tests\GridField\GridFieldTest\Team;
use SilverStripe\ORM\DataList;
use SilverStripe\ORM\DataObject;
class CommentsGridFieldActionTest extends SapphireTest
{
/** @var ArrayList */
protected $list;
@ -15,7 +29,7 @@ class CommentsGridFieldActionTest extends SapphireTest
public function setUp()
{
parent::setUp();
$this->list = new DataList('GridFieldAction_Delete_Team');
$this->list = new DataList(Team::class);
$config = CommentsGridFieldConfig::create()->addComponent(new GridFieldDeleteAction());
$this->gridField = new CommentsGridField('testfield', 'testfield', $this->list, $config);
$this->form = new Form(new Controller(), 'mockform', new FieldList(array($this->gridField)), new FieldList());
@ -41,7 +55,7 @@ class CommentsGridFieldActionTest extends SapphireTest
{
$action = new CommentsGridFieldAction();
$record = new Comment();
$attrs = $action->getColumnAttributes($this->gridField, $record, 'Comment');
$attrs = $action->getColumnAttributes($this->gridField, $record, Comment::class);
$this->assertEquals(array('class' => 'col-buttons'), $attrs);
}
@ -70,28 +84,25 @@ class CommentsGridFieldActionTest extends SapphireTest
$record->Comment = 'This is a comment';
$record->write();
$recordID = $record->ID;
$html = $action->getColumnContent($this->gridField, $record, 'Comment');
$this->assertContains('data-url="Controller/mockform/field/testfield',
$html);
$spamAction = 'value="Spam" class="action" id="action_CustomAction' .
$recordID . 'Spam"';
$html = $action->getColumnContent($this->gridField, $record, Comment::class);
$this->assertContains('data-url="Controller/mockform/field/testfield', $html);
$spamAction = 'value="Spam" class="action" id="action_CustomAction' . $recordID . 'Spam"';
$this->assertContains($spamAction, $html);
$approveAction = 'value="Approve" class="action" id="action_CustomAction' .
$recordID . 'Approve"';
$approveAction = 'value="Approve" class="action" id="action_CustomAction' . $recordID . 'Approve"';
$this->assertContains($approveAction, $html);
// If marked as spam, only the approve button should be available
$record->markSpam();
$record->write();
$html = $action->getColumnContent($this->gridField, $record, 'Comment');
$html = $action->getColumnContent($this->gridField, $record, Comment::class);
$this->assertContains($approveAction, $html);
$this->assertNotContains($spamAction, $html);
// If marked as spam, only the approve button should be available
$record->markApproved();
$record->write();
$html = $action->getColumnContent($this->gridField, $record, 'Comment');
$html = $action->getColumnContent($this->gridField, $record, Comment::class);
$this->assertNotContains($approveAction, $html);
$this->assertContains($spamAction, $html);
}
@ -103,12 +114,11 @@ class CommentsGridFieldActionTest extends SapphireTest
$this->assertEquals(array('spam', 'approve'), $result);
}
public function testHandleAction()
{
$action = new CommentsGridFieldAction();
$record = new Comment();
$record->Name = 'Name of commeter';
$record->Name = 'Name of commenter';
$record->Comment = 'This is a comment';
$record->write();
$recordID = $record->ID;
@ -120,11 +130,11 @@ class CommentsGridFieldActionTest extends SapphireTest
'Comment marked as spam.',
Controller::curr()->getResponse()->getStatusDescription()
);
$record = DataObject::get_by_id('Comment', $recordID);
$record = DataObject::get_by_id(Comment::class, $recordID);
$this->assertEquals(1, $record->Moderated);
$this->assertEquals(1, $record->IsSpam);
//getStatusDescription
//getStatusDescription
$result = $action->handleAction($this->gridField, 'approve', $arguments, $data);
$this->assertEquals(200, Controller::curr()->getResponse()->getStatusCode());
$this->assertEquals(
@ -132,10 +142,8 @@ class CommentsGridFieldActionTest extends SapphireTest
Controller::curr()->getResponse()->getStatusDescription()
);
$record = DataObject::get_by_id('Comment', $recordID);
$record = DataObject::get_by_id(Comment::class, $recordID);
$this->assertEquals(1, $record->Moderated);
$this->assertEquals(0, $record->IsSpam);
error_log(Controller::curr()->getResponse()->getStatusCode());
}
}

View File

@ -1,5 +1,9 @@
<?php
namespace SilverStripe\Comments\Tests;
use SilverStripe\Dev\SapphireTest;
class CommentsGridFieldBulkActionTest extends SapphireTest
{
public function testSpam()

View File

@ -1,10 +1,14 @@
<?php
namespace SilverStripe\Comments\Tests;
use SilverStripe\Dev\SapphireTest;
class CommentsGridFieldConfigTest extends SapphireTest
{
public function test__construct()
public function testConstruct()
{
$config = new CommentsGridFieldConfigTest();
// $config = new CommentsGridFieldConfigTest();
$this->markTestSkipped('TODO');
}
}

View File

@ -1,17 +1,24 @@
<?php
namespace SilverStripe\Comments\Tests;
use ReflectionClass;
use ReflectionException;
use SilverStripe\Comments\Model\Comment;
use SilverStripe\Comments\Admin\CommentsGridField;
use SilverStripe\Dev\SapphireTest;
class CommentsGridFieldTest extends SapphireTest
{
public function testNewRow()
{
$gridfield = new CommentsGridField('testfield', 'testfield');
// protected function newRow($total, $index, $record, $attributes, $content) {
$comment = new Comment();
// protected function newRow($total, $index, $record, $attributes, $content) {
$comment = new Comment();
$comment->Name = 'Fred Bloggs';
$comment->Comment = 'This is a comment';
$attr = array();
try {
$class = new ReflectionClass($gridfield);
$method = $class->getMethod('newRow');

View File

@ -1,17 +1,37 @@
<?php
namespace SilverStripe\Comments\Tests;
use ReflectionClass;
use SilverStripe\Comments\Extensions\CommentsExtension;
use SilverStripe\Comments\Model\Comment;
use SilverStripe\Comments\Tests\Stubs\CommentableItem;
use SilverStripe\Comments\Tests\Stubs\CommentableItemDisabled;
use SilverStripe\Comments\Tests\Stubs\CommentableItemEnabled;
use SilverStripe\Control\Controller;
use SilverStripe\Control\Director;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Email\Email;
use SilverStripe\Dev\FunctionalTest;
use SilverStripe\Dev\TestOnly;
use SilverStripe\i18n\i18n;
use SilverStripe\ORM\DataObject;
use SilverStripe\Security\Member;
use SilverStripe\Security\Permission;
/**
* @package comments
*/
class CommentsTest extends FunctionalTest
{
public static $fixture_file = 'comments/tests/CommentsTest.yml';
protected $extraDataObjects = array(
'CommentableItem',
'CommentableItemEnabled',
'CommentableItemDisabled'
CommentableItem::class,
CommentableItemEnabled::class,
CommentableItemDisabled::class
);
public function setUp()
@ -20,7 +40,7 @@ class CommentsTest extends FunctionalTest
Config::nest();
// Set good default values
Config::inst()->update('CommentsExtension', 'comments', array(
Config::inst()->update(CommentsExtension::class, 'comments', array(
'enabled' => true,
'enabled_cms' => false,
'require_login' => false,
@ -34,7 +54,7 @@ class CommentsTest extends FunctionalTest
));
// Configure this dataobject
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'enabled_cms' => true
));
}
@ -49,13 +69,13 @@ class CommentsTest extends FunctionalTest
{
// comments don't require moderation so unmoderated comments can be
// shown but not spam posts
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'require_moderation_nonmembers' => false,
'require_moderation' => false,
'require_moderation_cms' => false,
));
$item = $this->objFromFixture('CommentableItem', 'spammed');
$item = $this->objFromFixture(CommentableItem::class, 'spammed');
$this->assertEquals('None', $item->ModerationRequired);
$this->assertDOSEquals(array(
@ -64,11 +84,11 @@ class CommentsTest extends FunctionalTest
), $item->Comments(), 'Only 2 non spam posts should be shown');
// when moderated, only moderated, non spam posts should be shown.
Config::inst()->update('CommentableItem', 'comments', array('require_moderation_nonmembers' => true));
Config::inst()->update(CommentableItem::class, 'comments', array('require_moderation_nonmembers' => true));
$this->assertEquals('NonMembersOnly', $item->ModerationRequired);
// Check that require_moderation overrides this option
Config::inst()->update('CommentableItem', 'comments', array('require_moderation' => true));
Config::inst()->update(CommentableItem::class, 'comments', array('require_moderation' => true));
$this->assertEquals('Required', $item->ModerationRequired);
$this->assertDOSEquals(array(
@ -77,14 +97,14 @@ class CommentsTest extends FunctionalTest
$this->assertEquals(1, $item->Comments()->Count());
// require_moderation_nonmembers still filters out unmoderated comments
Config::inst()->update('CommentableItem', 'comments', array('require_moderation' => false));
Config::inst()->update(CommentableItem::class, 'comments', array('require_moderation' => false));
$this->assertEquals(1, $item->Comments()->Count());
Config::inst()->update('CommentableItem', 'comments', array('require_moderation_nonmembers' => false));
Config::inst()->update(CommentableItem::class, 'comments', array('require_moderation_nonmembers' => false));
$this->assertEquals(2, $item->Comments()->Count());
// With unmoderated comments set to display in frontend
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'require_moderation' => true,
'frontend_moderation' => true
));
@ -94,7 +114,7 @@ class CommentsTest extends FunctionalTest
$this->assertEquals(2, $item->Comments()->Count());
// With spam comments set to display in frontend
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'require_moderation' => true,
'frontend_moderation' => false,
'frontend_spam' => true,
@ -109,7 +129,7 @@ class CommentsTest extends FunctionalTest
// With spam and unmoderated comments set to display in frontend
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'require_moderation' => true,
'frontend_moderation' => true,
'frontend_spam' => true,
@ -130,12 +150,12 @@ class CommentsTest extends FunctionalTest
{
// comments don't require moderation so unmoderated comments can be
// shown but not spam posts
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'require_moderation' => true,
'require_moderation_cms' => true,
));
$item = $this->objFromFixture('CommentableItem', 'spammed');
$item = $this->objFromFixture(CommentableItem::class, 'spammed');
$this->assertEquals('None', $item->ModerationRequired);
$this->assertDOSEquals(array(
@ -170,13 +190,13 @@ class CommentsTest extends FunctionalTest
public function testCanPostComment()
{
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'require_login' => false,
'require_login_cms' => false,
'required_permission' => false,
));
$item = $this->objFromFixture('CommentableItem', 'first');
$item2 = $this->objFromFixture('CommentableItem', 'second');
$item = $this->objFromFixture(CommentableItem::class, 'first');
$item2 = $this->objFromFixture(CommentableItem::class, 'second');
// Test restriction free commenting
if ($member = Member::currentUser()) {
@ -186,7 +206,7 @@ class CommentsTest extends FunctionalTest
$this->assertTrue($item->canPostComment());
// Test permission required to post
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'require_login' => true,
'required_permission' => 'POSTING_PERMISSION',
));
@ -200,7 +220,7 @@ class CommentsTest extends FunctionalTest
$this->assertTrue($item->canPostComment());
// Test require login to post, but not any permissions
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'required_permission' => false,
));
$this->assertTrue($item->CommentsRequireLogin);
@ -212,7 +232,7 @@ class CommentsTest extends FunctionalTest
$this->assertTrue($item->canPostComment());
// Test options set via CMS
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'require_login' => true,
'require_login_cms' => true,
));
@ -235,12 +255,12 @@ class CommentsTest extends FunctionalTest
if ($member = Member::currentUser()) {
$member->logOut();
}
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$commentID = $comment->ID;
$this->assertNull($comment->DeleteLink(), 'No permission to see delete link');
$delete = $this->get('CommentingController/delete/'.$comment->ID.'?ajax=1');
$delete = $this->get('comments/delete/' . $comment->ID . '?ajax=1');
$this->assertEquals(403, $delete->getStatusCode());
$check = DataObject::get_by_id('Comment', $commentID);
$check = DataObject::get_by_id(Comment::class, $commentID);
$this->assertTrue($check && $check->exists());
// Test non-authenticated user
@ -249,16 +269,16 @@ class CommentsTest extends FunctionalTest
// Test authenticated user
$this->logInAs('commentadmin');
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$commentID = $comment->ID;
$adminComment1Link = $comment->DeleteLink();
$this->assertContains('CommentingController/delete/'.$commentID.'?t=', $adminComment1Link);
$this->assertContains('comments/delete/' . $commentID . '?t=', $adminComment1Link);
// Test that this link can't be shared / XSS exploited
$this->logInAs('commentadmin2');
$delete = $this->get($adminComment1Link);
$this->assertEquals(400, $delete->getStatusCode());
$check = DataObject::get_by_id('Comment', $commentID);
$check = DataObject::get_by_id(Comment::class, $commentID);
$this->assertTrue($check && $check->exists());
// Test that this other admin can delete the comment with their own link
@ -267,7 +287,7 @@ class CommentsTest extends FunctionalTest
$this->autoFollowRedirection = false;
$delete = $this->get($adminComment2Link);
$this->assertEquals(302, $delete->getStatusCode());
$check = DataObject::get_by_id('Comment', $commentID);
$check = DataObject::get_by_id(Comment::class, $commentID);
$this->assertFalse($check && $check->exists());
}
@ -277,12 +297,12 @@ class CommentsTest extends FunctionalTest
if ($member = Member::currentUser()) {
$member->logOut();
}
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$commentID = $comment->ID;
$this->assertNull($comment->SpamLink(), 'No permission to see mark as spam link');
$spam = $this->get('CommentingController/spam/'.$comment->ID.'?ajax=1');
$spam = $this->get('comments/spam/'.$comment->ID.'?ajax=1');
$this->assertEquals(403, $spam->getStatusCode());
$check = DataObject::get_by_id('Comment', $commentID);
$check = DataObject::get_by_id(Comment::class, $commentID);
$this->assertEquals(0, $check->IsSpam, 'No permission to mark as spam');
// Test non-authenticated user
@ -291,16 +311,16 @@ class CommentsTest extends FunctionalTest
// Test authenticated user
$this->logInAs('commentadmin');
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$commentID = $comment->ID;
$adminComment1Link = $comment->SpamLink();
$this->assertContains('CommentingController/spam/'.$commentID.'?t=', $adminComment1Link);
$this->assertContains('comments/spam/' . $commentID . '?t=', $adminComment1Link);
// Test that this link can't be shared / XSS exploited
$this->logInAs('commentadmin2');
$spam = $this->get($adminComment1Link);
$this->assertEquals(400, $spam->getStatusCode());
$check = DataObject::get_by_id('Comment', $comment->ID);
$check = DataObject::get_by_id(Comment::class, $comment->ID);
$this->assertEquals(0, $check->IsSpam, 'No permission to mark as spam');
// Test that this other admin can spam the comment with their own link
@ -309,7 +329,7 @@ class CommentsTest extends FunctionalTest
$this->autoFollowRedirection = false;
$spam = $this->get($adminComment2Link);
$this->assertEquals(302, $spam->getStatusCode());
$check = DataObject::get_by_id('Comment', $commentID);
$check = DataObject::get_by_id(Comment::class, $commentID);
$this->assertEquals(1, $check->IsSpam);
// Cannot re-spam spammed comment
@ -322,12 +342,12 @@ class CommentsTest extends FunctionalTest
if ($member = Member::currentUser()) {
$member->logOut();
}
$comment = $this->objFromFixture('Comment', 'secondComC');
$comment = $this->objFromFixture(Comment::class, 'secondComC');
$commentID = $comment->ID;
$this->assertNull($comment->HamLink(), 'No permission to see mark as ham link');
$ham = $this->get('CommentingController/ham/'.$comment->ID.'?ajax=1');
$ham = $this->get('comments/ham/' . $comment->ID . '?ajax=1');
$this->assertEquals(403, $ham->getStatusCode());
$check = DataObject::get_by_id('Comment', $commentID);
$check = DataObject::get_by_id(Comment::class, $commentID);
$this->assertEquals(1, $check->IsSpam, 'No permission to mark as ham');
// Test non-authenticated user
@ -336,16 +356,16 @@ class CommentsTest extends FunctionalTest
// Test authenticated user
$this->logInAs('commentadmin');
$comment = $this->objFromFixture('Comment', 'secondComC');
$comment = $this->objFromFixture(Comment::class, 'secondComC');
$commentID = $comment->ID;
$adminComment1Link = $comment->HamLink();
$this->assertContains('CommentingController/ham/'.$commentID.'?t=', $adminComment1Link);
$this->assertContains('comments/ham/' . $commentID . '?t=', $adminComment1Link);
// Test that this link can't be shared / XSS exploited
$this->logInAs('commentadmin2');
$ham = $this->get($adminComment1Link);
$this->assertEquals(400, $ham->getStatusCode());
$check = DataObject::get_by_id('Comment', $comment->ID);
$check = DataObject::get_by_id(Comment::class, $comment->ID);
$this->assertEquals(1, $check->IsSpam, 'No permission to mark as ham');
// Test that this other admin can ham the comment with their own link
@ -354,7 +374,7 @@ class CommentsTest extends FunctionalTest
$this->autoFollowRedirection = false;
$ham = $this->get($adminComment2Link);
$this->assertEquals(302, $ham->getStatusCode());
$check = DataObject::get_by_id('Comment', $commentID);
$check = DataObject::get_by_id(Comment::class, $commentID);
$this->assertEquals(0, $check->IsSpam);
// Cannot re-ham hammed comment
@ -367,12 +387,12 @@ class CommentsTest extends FunctionalTest
if ($member = Member::currentUser()) {
$member->logOut();
}
$comment = $this->objFromFixture('Comment', 'secondComB');
$comment = $this->objFromFixture(Comment::class, 'secondComB');
$commentID = $comment->ID;
$this->assertNull($comment->ApproveLink(), 'No permission to see approve link');
$approve = $this->get('CommentingController/approve/'.$comment->ID.'?ajax=1');
$approve = $this->get('comments/approve/' . $comment->ID . '?ajax=1');
$this->assertEquals(403, $approve->getStatusCode());
$check = DataObject::get_by_id('Comment', $commentID);
$check = DataObject::get_by_id(Comment::class, $commentID);
$this->assertEquals(0, $check->Moderated, 'No permission to approve');
// Test non-authenticated user
@ -381,16 +401,16 @@ class CommentsTest extends FunctionalTest
// Test authenticated user
$this->logInAs('commentadmin');
$comment = $this->objFromFixture('Comment', 'secondComB');
$comment = $this->objFromFixture(Comment::class, 'secondComB');
$commentID = $comment->ID;
$adminComment1Link = $comment->ApproveLink();
$this->assertContains('CommentingController/approve/'.$commentID.'?t=', $adminComment1Link);
$this->assertContains('comments/approve/' . $commentID . '?t=', $adminComment1Link);
// Test that this link can't be shared / XSS exploited
$this->logInAs('commentadmin2');
$approve = $this->get($adminComment1Link);
$this->assertEquals(400, $approve->getStatusCode());
$check = DataObject::get_by_id('Comment', $comment->ID);
$check = DataObject::get_by_id(Comment::class, $comment->ID);
$this->assertEquals(0, $check->Moderated, 'No permission to approve');
// Test that this other admin can approve the comment with their own link
@ -399,7 +419,7 @@ class CommentsTest extends FunctionalTest
$this->autoFollowRedirection = false;
$approve = $this->get($adminComment2Link);
$this->assertEquals(302, $approve->getStatusCode());
$check = DataObject::get_by_id('Comment', $commentID);
$check = DataObject::get_by_id(Comment::class, $commentID);
$this->assertEquals(1, $check->Moderated);
// Cannot re-approve approved comment
@ -427,21 +447,21 @@ class CommentsTest extends FunctionalTest
public function testSanitizesWithAllowHtml()
{
if (!class_exists('HTMLPurifier')) {
if (!class_exists('\\HTMLPurifier')) {
$this->markTestSkipped('HTMLPurifier class not found');
return;
}
// Add p for paragraph
// NOTE: The config method appears to append to the existing array
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'html_allowed_elements' => array('p'),
));
// Without HTML allowed
$comment1 = new Comment();
$comment1->AllowHtml = false;
$comment1->BaseClass = 'CommentableItem';
$comment1->BaseClass = CommentableItem::class;
$comment1->Comment = '<p><script>alert("w00t")</script>my comment</p>';
$comment1->write();
$this->assertEquals(
@ -454,7 +474,7 @@ class CommentsTest extends FunctionalTest
// With HTML allowed
$comment2 = new Comment();
$comment2->AllowHtml = true;
$comment2->BaseClass = 'CommentableItem';
$comment2->ParentClass = CommentableItem::class;
$comment2->Comment = '<p><script>alert("w00t")</script>my comment</p>';
$comment2->write();
$this->assertEquals(
@ -466,11 +486,11 @@ class CommentsTest extends FunctionalTest
public function testDefaultTemplateRendersHtmlWithAllowHtml()
{
if (!class_exists('HTMLPurifier')) {
if (!class_exists('\\HTMLPurifier')) {
$this->markTestSkipped('HTMLPurifier class not found');
}
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'html_allowed_elements' => array('p'),
));
@ -482,7 +502,7 @@ class CommentsTest extends FunctionalTest
$comment->Comment = '<p>my comment</p>';
$comment->AllowHtml = false;
$comment->ParentID = $item->ID;
$comment->BaseClass = 'CommentableItem';
$comment->BaseClass = CommentableItem::class;
$comment->write();
$html = $item->customise(array('CommentsEnabled' => true))->renderWith('CommentsInterface');
@ -507,7 +527,7 @@ class CommentsTest extends FunctionalTest
public function testDefaultEnabled()
{
// Ensure values are set via cms (not via config)
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'enabled_cms' => true,
'require_moderation_cms' => true,
'require_login_cms' => true
@ -532,13 +552,13 @@ class CommentsTest extends FunctionalTest
// With default = false
// Because of config rules about falsey values, apply config to object directly
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'enabled' => false,
'require_login' => true,
'require_moderation' => true
));
$obj = new CommentableItem();
$this->assertFalse((bool)$obj->getCommentsOption('enabled'), "Default setting is disabled");
$this->assertFalse((bool)$obj->getCommentsOption('enabled'), 'Default setting is disabled');
$this->assertFalse((bool)$obj->ProvideComments);
$this->assertEquals('Required', $obj->ModerationRequired);
$this->assertTrue((bool)$obj->CommentsRequireLogin);
@ -559,7 +579,7 @@ class CommentsTest extends FunctionalTest
*/
public function testOnBeforeDelete()
{
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$child = new Comment();
$child->Name = 'Fred Bloggs';
@ -574,8 +594,8 @@ class CommentsTest extends FunctionalTest
$comment->delete();
// assert that the new child been deleted
$this->assertFalse(DataObject::get_by_id('Comment', $commentID));
$this->assertFalse(DataObject::get_by_id('Comment', $childCommentID));
$this->assertFalse(DataObject::get_by_id(Comment::class, $commentID));
$this->assertFalse(DataObject::get_by_id(Comment::class, $childCommentID));
}
public function testRequireDefaultRecords()
@ -585,41 +605,42 @@ class CommentsTest extends FunctionalTest
public function testLink()
{
$comment = $this->objFromFixture('Comment', 'thirdComD');
$this->assertEquals('CommentableItem_Controller#comment-'.$comment->ID,
$comment->Link());
$comment = $this->objFromFixture(Comment::class, 'thirdComD');
$this->assertEquals(
'CommentableItemController#comment-' . $comment->ID,
$comment->Link()
);
$this->assertEquals($comment->ID, $comment->ID);
// An orphan comment has no link
$comment->ParentID = 0;
$comment->ParentClass = null;
$comment->write();
$this->assertEquals('', $comment->Link());
}
public function testPermalink()
{
$comment = $this->objFromFixture('Comment', 'thirdComD');
$comment = $this->objFromFixture(Comment::class, 'thirdComD');
$this->assertEquals('comment-' . $comment->ID, $comment->Permalink());
}
/*
Test field labels in 2 languages
/**
* Test field labels in 2 languages
*/
public function testFieldLabels()
{
$locale = i18n::get_locale();
i18n::set_locale('fr');
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$labels = $comment->FieldLabels();
$expected = array(
'Name' => 'Nom de l\'Auteur',
'Comment' => 'Commentaire',
'Email' => 'Email',
'URL' => 'URL',
'BaseClass' => 'Base Class',
'Moderated' => 'Modéré?',
'IsSpam' => 'Spam?',
'ParentID' => 'Parent ID',
'AllowHtml' => 'Allow Html',
'SecretToken' => 'Secret Token',
'Depth' => 'Depth',
@ -627,7 +648,8 @@ class CommentsTest extends FunctionalTest
'ParentComment' => 'Parent Comment',
'ChildComments' => 'Child Comments',
'ParentTitle' => 'Parent',
'Created' => 'Date de publication'
'Created' => 'Date de publication',
'Parent' => 'Parent'
);
i18n::set_locale($locale);
$this->assertEquals($expected, $labels);
@ -637,10 +659,8 @@ class CommentsTest extends FunctionalTest
'Comment' => 'Comment',
'Email' => 'Email',
'URL' => 'URL',
'BaseClass' => 'Base Class',
'Moderated' => 'Moderated?',
'IsSpam' => 'Spam?',
'ParentID' => 'Parent ID',
'AllowHtml' => 'Allow Html',
'SecretToken' => 'Secret Token',
'Depth' => 'Depth',
@ -648,8 +668,8 @@ class CommentsTest extends FunctionalTest
'ParentComment' => 'Parent Comment',
'ChildComments' => 'Child Comments',
'ParentTitle' => 'Parent',
'Created' => 'Date posted'
'Created' => 'Date posted',
'Parent' => 'Parent'
);
$this->assertEquals($expected, $labels);
}
@ -661,29 +681,31 @@ class CommentsTest extends FunctionalTest
public function testGetParent()
{
$comment = $this->objFromFixture('Comment', 'firstComA');
$item = $this->objFromFixture('CommentableItem', 'first');
$parent = $comment->getParent();
$this->assertEquals($item, $parent);
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$item = $this->objFromFixture(CommentableItem::class, 'first');
$parent = $comment->Parent();
$this->assertSame($item->getClassName(), $parent->getClassName());
$this->assertSame($item->ID, $parent->ID);
}
public function testGetParentTitle()
{
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$title = $comment->getParentTitle();
$this->assertEquals('First', $title);
// Title from a comment with no parent is blank
$comment->ParentID = 0;
$comment->ParentClass = null;
$comment->write();
$this->assertEquals('', $comment->getParentTitle());
}
public function testGetParentClassName()
{
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$className = $comment->getParentClassName();
$this->assertEquals('CommentableItem', $className);
$this->assertEquals(CommentableItem::class, $className);
}
public function testCastingHelper()
@ -708,7 +730,7 @@ class CommentsTest extends FunctionalTest
public function testCanCreate()
{
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
// admin can create - this is always false
$this->logInAs('commentadmin');
@ -721,7 +743,7 @@ class CommentsTest extends FunctionalTest
public function testCanView()
{
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
// admin can view
$this->logInAs('commentadmin');
@ -738,7 +760,7 @@ class CommentsTest extends FunctionalTest
public function testCanEdit()
{
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
// admin can edit
$this->logInAs('commentadmin');
@ -755,7 +777,7 @@ class CommentsTest extends FunctionalTest
public function testCanDelete()
{
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
// admin can delete
$this->logInAs('commentadmin');
@ -774,7 +796,7 @@ class CommentsTest extends FunctionalTest
{
$this->logInAs('visitor');
$current = Member::currentUser();
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$method = $this->getMethod('getMember');
// null case
@ -792,7 +814,7 @@ class CommentsTest extends FunctionalTest
public function testGetAuthorName()
{
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$this->assertEquals(
'FA',
$comment->getAuthorName()
@ -804,7 +826,7 @@ class CommentsTest extends FunctionalTest
$comment->getAuthorName()
);
$author = $this->objFromFixture('Member', 'visitor');
$author = $this->objFromFixture(Member::class, 'visitor');
$comment->AuthorID = $author->ID;
$comment->write();
$this->assertEquals(
@ -821,44 +843,44 @@ class CommentsTest extends FunctionalTest
public function testLinks()
{
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$this->logInAs('commentadmin');
$method = $this->getMethod('ActionLink');
// test with starts of strings and tokens and salts change each time
$this->assertStringStartsWith(
'/CommentingController/theaction/'.$comment->ID,
'/comments/theaction/' . $comment->ID,
$method->invokeArgs($comment, array('theaction'))
);
$this->assertStringStartsWith(
'/CommentingController/delete/'.$comment->ID,
'/comments/delete/' . $comment->ID,
$comment->DeleteLink()
);
$this->assertStringStartsWith(
'/CommentingController/spam/'.$comment->ID,
'/comments/spam/' . $comment->ID,
$comment->SpamLink()
);
$comment->markSpam();
$this->assertStringStartsWith(
'/CommentingController/ham/'.$comment->ID,
'/comments/ham/' . $comment->ID,
$comment->HamLink()
);
//markApproved
$comment->markUnapproved();
$this->assertStringStartsWith(
'/CommentingController/approve/'.$comment->ID,
'/comments/approve/' . $comment->ID,
$comment->ApproveLink()
);
}
public function testMarkSpam()
{
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$comment->markSpam();
$this->assertTrue($comment->Moderated);
$this->assertTrue($comment->IsSpam);
@ -866,7 +888,7 @@ class CommentsTest extends FunctionalTest
public function testMarkApproved()
{
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$comment->markApproved();
$this->assertTrue($comment->Moderated);
$this->assertFalse($comment->IsSpam);
@ -874,14 +896,14 @@ class CommentsTest extends FunctionalTest
public function testMarkUnapproved()
{
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$comment->markApproved();
$this->assertTrue($comment->Moderated);
}
public function testSpamClass()
{
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$this->assertEquals('notspam', $comment->spamClass());
$comment->Moderated = false;
$this->assertEquals('unmoderated', $comment->spamClass());
@ -891,7 +913,7 @@ class CommentsTest extends FunctionalTest
public function testGetTitle()
{
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$this->assertEquals(
'Comment by FA on First',
$comment->getTitle()
@ -900,7 +922,7 @@ class CommentsTest extends FunctionalTest
public function testGetCMSFields()
{
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$fields = $comment->getCMSFields();
$names = array();
foreach ($fields as $field) {
@ -912,7 +934,7 @@ class CommentsTest extends FunctionalTest
'Comment',
'Email',
'URL',
null #FIXME this is suspicious
'Options'
);
$this->assertEquals($expected, $names);
}
@ -920,7 +942,7 @@ class CommentsTest extends FunctionalTest
public function testGetCMSFieldsCommentHasAuthor()
{
$member = Member::get()->filter('FirstName', 'visitor')->first();
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$comment->AuthorID = $member->ID;
$comment->write();
@ -936,14 +958,14 @@ class CommentsTest extends FunctionalTest
'Comment',
'Email',
'URL',
null #FIXME this is suspicious
'Options'
);
$this->assertEquals($expected, $names);
}
public function testGetCMSFieldsWithParentComment()
{
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$child = new Comment();
$child->Name = 'John Smith';
@ -962,7 +984,7 @@ class CommentsTest extends FunctionalTest
'Comment',
'Email',
'URL',
null, #FIXME this is suspicious
'Options',
'ParentComment_Title',
'ParentComment_Created',
'ParentComment_AuthorName',
@ -971,10 +993,9 @@ class CommentsTest extends FunctionalTest
$this->assertEquals($expected, $names);
}
public function testPurifyHtml()
{
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$dirtyHTML = '<p><script>alert("w00t")</script>my comment</p>';
$this->assertEquals(
@ -986,22 +1007,22 @@ class CommentsTest extends FunctionalTest
public function testGravatar()
{
// Turn gravatars on
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'use_gravatar' => true
));
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$this->assertEquals(
'http://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e?s'.
'=80&d=identicon&r=g',
'http://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e?s'
. '=80&d=identicon&r=g',
$comment->gravatar()
);
// Turn gravatars off
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'use_gravatar' => false
));
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$this->assertEquals(
'',
@ -1011,13 +1032,13 @@ class CommentsTest extends FunctionalTest
public function testGetRepliesEnabled()
{
$comment = $this->objFromFixture('Comment', 'firstComA');
Config::inst()->update('CommentableItem', 'comments', array(
$comment = $this->objFromFixture(Comment::class, 'firstComA');
Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => false
));
$this->assertFalse($comment->getRepliesEnabled());
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => true,
'nested_depth' => 4
));
@ -1028,7 +1049,7 @@ class CommentsTest extends FunctionalTest
// 0 indicates no limit for nested_depth
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => true,
'nested_depth' => 0
));
@ -1046,11 +1067,11 @@ class CommentsTest extends FunctionalTest
public function testAllReplies()
{
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => true,
'nested_depth' => 4
));
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$this->assertEquals(
3,
$comment->allReplies()->count()
@ -1069,7 +1090,7 @@ class CommentsTest extends FunctionalTest
$comment->allReplies()->count()
);
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => false
));
@ -1078,13 +1099,13 @@ class CommentsTest extends FunctionalTest
public function testReplies()
{
CommentableItem::add_extension('CommentsExtension');
CommentableItem::add_extension(CommentsExtension::class);
$this->logInWithPermission('ADMIN');
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => true,
'nested_depth' => 4
));
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$this->assertEquals(
3,
$comment->Replies()->count()
@ -1114,17 +1135,17 @@ class CommentsTest extends FunctionalTest
// Test moderation required on the front end
$item = $this->objFromFixture('CommentableItem', 'first');
$item = $this->objFromFixture(CommentableItem::class, 'first');
$item->ModerationRequired = 'Required';
$item->write();
Config::inst()->update('CommentableItemDisabled', 'comments', array(
Config::inst()->update(CommentableItemDisabled::class, 'comments', array(
'nested_comments' => true,
'nested_depth' => 4,
'frontend_moderation' => true
));
$comment = DataObject::get_by_id('Comment', $comment->ID);
$comment = DataObject::get_by_id(Comment::class, $comment->ID);
$this->assertEquals(
2,
@ -1132,7 +1153,7 @@ class CommentsTest extends FunctionalTest
);
// Turn off nesting, empty array should be returned
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => false
));
@ -1141,18 +1162,18 @@ class CommentsTest extends FunctionalTest
$comment->Replies()->count()
);
CommentableItem::remove_extension('CommentsExtension');
CommentableItem::remove_extension(CommentsExtension::class);
}
public function testPagedReplies()
{
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => true,
'nested_depth' => 4,
'comments_per_page' => 2 #Force 2nd page for 3 items
));
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$pagedList = $comment->pagedReplies();
$this->assertEquals(
2,
@ -1164,7 +1185,7 @@ class CommentsTest extends FunctionalTest
);
//TODO - 2nd page requires controller
//
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => false
));
@ -1173,19 +1194,19 @@ class CommentsTest extends FunctionalTest
public function testReplyForm()
{
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => false,
'nested_depth' => 4
));
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
// No nesting, no reply form
$form = $comment->replyForm();
$this->assertNull($form);
// parent item so show form
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => true,
'nested_depth' => 4
));
@ -1198,11 +1219,11 @@ class CommentsTest extends FunctionalTest
$this->assertEquals(
array(
null, #FIXME suspicious
'NameEmailURLComment', // The CompositeField name?
'ParentID',
'ParentClassName',
'ReturnURL',
'ParentCommentID',
'BaseClass'
'ParentCommentID'
),
$names
);
@ -1210,6 +1231,7 @@ class CommentsTest extends FunctionalTest
// no parent, no reply form
$comment->ParentID = 0;
$comment->ParentClass = null;
$comment->write();
$form = $comment->replyForm();
$this->assertNull($form);
@ -1217,12 +1239,12 @@ class CommentsTest extends FunctionalTest
public function testUpdateDepth()
{
Config::inst()->update('CommentableItem', 'comments', array(
Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => true,
'nested_depth' => 4
));
$comment = $this->objFromFixture('Comment', 'firstComA');
$comment = $this->objFromFixture(Comment::class, 'firstComA');
$children = $comment->allReplies()->toArray();
// Make the second child a child of the first
// Make the third child a child of the second
@ -1262,98 +1284,11 @@ class CommentsTest extends FunctionalTest
$this->markTestSkipped('TODO');
}
protected static function getMethod($name)
{
$class = new ReflectionClass('Comment');
$class = new ReflectionClass(Comment::class);
$method = $class->getMethod($name);
$method->setAccessible(true);
return $method;
}
}
/**
* @package comments
* @subpackage tests
*/
class CommentableItem extends DataObject implements TestOnly
{
private static $db = array(
'Title' => 'Varchar'
);
private static $extensions = array(
'CommentsExtension'
);
public function RelativeLink()
{
return "CommentableItem_Controller";
}
public function canView($member = null)
{
return true;
}
// This is needed for canModerateComments
public function canEdit($member = null)
{
if ($member instanceof Member) {
$memberID = $member->ID;
} elseif (is_numeric($member)) {
$memberID = $member;
} else {
$memberID = Member::currentUserID();
}
if ($memberID && Permission::checkMember($memberID, array("ADMIN", "CMS_ACCESS_CommentAdmin"))) {
return true;
}
return false;
}
public function Link()
{
return $this->RelativeLink();
}
public function AbsoluteLink()
{
return Director::absoluteURL($this->RelativeLink());
}
}
class CommentableItemEnabled extends CommentableItem
{
private static $defaults = array(
'ProvideComments' => true,
'ModerationRequired' => 'Required',
'CommentsRequireLogin' => true
);
}
class CommentableItemDisabled extends CommentableItem
{
private static $defaults = array(
'ProvideComments' => false,
'ModerationRequired' => 'None',
'CommentsRequireLogin' => false
);
}
/**
* @package comments
* @subpackage tests
*/
class CommentableItem_Controller extends Controller implements TestOnly
{
public function index()
{
return CommentableItem::get()->first()->CommentsForm();
}
}

View File

@ -1,4 +1,4 @@
Member:
SilverStripe\Security\Member:
commentadmin:
FirstName: admin
commentadmin2:
@ -6,17 +6,17 @@ Member:
visitor:
FirstName: visitor
Group:
SilverStripe\Security\Group:
commentadmins:
Title: Admin
Members: =>Member.commentadmin, =>Member.commentadmin2
Members: =>SilverStripe\Security\Member.commentadmin, =>SilverStripe\Security\Member.commentadmin2
Permission:
SilverStripe\Security\Permission:
admin:
Code: CMS_ACCESS_CommentAdmin
Group: =>Group.commentadmins
Group: =>SilverStripe\Security\Group.commentadmins
CommentableItem:
SilverStripe\Comments\Tests\Stubs\CommentableItem:
first:
Title: First
ProvideComments: 1
@ -35,166 +35,158 @@ CommentableItem:
ProvideComments: 1
Title: spammed
ModerationRequired: 'None'
moderated:
ProvideComments: 1
Title: Moderate everything
ModerationRequired: Required
CommentsRequireLogin: 0
Comment:
SilverStripe\Comments\Model\Comment:
firstComA:
ParentID: =>CommentableItem.first
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.first
Name: FA
Comment: textFA
BaseClass: CommentableItem
Moderated: 1
IsSpam:
Depth: 1
firstComAChild1:
ParentID: =>CommentableItem.first
ParentCommentID: =>Comment.firstComA
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.first
ParentComment: =>SilverStripe\Comments\Model\Comment.firstComA
Name: John Smith
Comment: Reply to firstComA 1
BaseClass: CommentableItem
Moderated: 1
IsSpam: 0
Depth: 2
firstComAChild2:
ParentID: =>CommentableItem.first
ParentCommentID: =>Comment.firstComA
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.first
ParentComment: =>SilverStripe\Comments\Model\Comment.firstComA
Name: John Smith
Comment: Reply to firstComA 2
BaseClass: CommentableItem
Moderated: 1
IsSpam: 0
Depth: 2
firstComAChild3:
ParentID: =>CommentableItem.first
ParentCommentID: =>Comment.firstComA
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.first
ParentComment: =>SilverStripe\Comments\Model\Comment.firstComA
Name: John Smith
Comment: Reply to firstComA 3
BaseClass: CommentableItem
Moderated: 1
IsSpam: 0
Depth: 2
secondComA:
ParentID: =>CommentableItem.second
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.second
Name: SA
Comment: textSA
Moderated: 1
IsSpam: 0
BaseClass: CommentableItem
secondComB:
ParentID: =>CommentableItem.second
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.second
Name: SB
Comment: textSB
Moderated: 0
IsSpam: 0
BaseClass: CommentableItem
secondComC:
ParentID: =>CommentableItem.second
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.second
Name: SB
Comment: textSB
Moderated: 1
IsSpam: 1
BaseClass: CommentableItem
thirdComA:
ParentID: =>CommentableItem.third
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TA
Comment: textTA
Moderated: 1
IsSpam: 0
BaseClass: CommentableItem
thirdComB:
ParentID: =>CommentableItem.third
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TB
Comment: textTB
Moderated: 1
IsSpam: 0
BaseClass: CommentableItem
thirdComC:
ParentID: =>CommentableItem.third
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TC
Comment: textTC
Moderated: 1
IsSpam: 0
BaseClass: CommentableItem
thirdComD:
ParentID: =>CommentableItem.third
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TC
Comment: textTC
Moderated: 1
BaseClass: CommentableItem
thirdComE:
ParentID: =>CommentableItem.third
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TC
Comment: textTC
Moderated: 1
BaseClass: CommentableItem
thirdComF:
ParentID: =>CommentableItem.third
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TC
Comment: textTC
Moderated: 1
IsSpam: 0
BaseClass: CommentableItem
thirdComG:
ParentID: =>CommentableItem.third
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TC
Comment: textTC
Moderated: 1
IsSpam: 0
BaseClass: CommentableItem
thirdComH:
ParentID: =>CommentableItem.third
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TC
Comment: textTC
Moderated: 1
IsSpam: 0
BaseClass: CommentableItem
thirdComI:
ParentID: =>CommentableItem.third
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TC
Comment: textTC
Moderated: 1
IsSpam: 0
BaseClass: CommentableItem
thirdComJ:
ParentID: =>CommentableItem.third
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TC
Comment: textTC
Moderated: 1
IsSpam: 0
BaseClass: CommentableItem
thirdComK:
ParentID: =>CommentableItem.third
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TC
Comment: textTC
Moderated: 1
IsSpam: 0
BaseClass: CommentableItem
disabledCom:
ParentID: =>CommentableItem.nocomments
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.nocomments
Name: Disabled
Moderated: 0
IsSpam: 1
BaseClass: CommentableItem
testCommentList1:
ParentID: =>CommentableItem.spammed
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.spammed
Name: Comment 1
Moderated: 0
IsSpam: 0
BaseClass: CommentableItem
testCommentList2:
ParentID: =>CommentableItem.spammed
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.spammed
Name: Comment 2
Moderated: 1
IsSpam: 1
BaseClass: CommentableItem
testCommentList3:
ParentID: =>CommentableItem.spammed
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.spammed
Name: Comment 3
Moderated: 1
IsSpam: 0
BaseClass: CommentableItem
testCommentList4:
ParentID: =>CommentableItem.spammed
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.spammed
Name: Comment 4
Moderated: 0
IsSpam: 1
BaseClass: CommentableItem
testModeratedComment1:
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.moderated
Name: Moderated comment 1
Moderated: 0
IsSpam: 0
testModeratedComment2:
Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.moderated
Name: Moderated comment 2
Moderated: 0
IsSpam: 1

View File

@ -0,0 +1,62 @@
<?php
namespace SilverStripe\Comments\Tests\Stubs;
use SilverStripe\Comments\Extensions\CommentsExtension;
use SilverStripe\Control\Director;
use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\DataObject;
use SilverStripe\Security\Member;
use SilverStripe\Security\Permission;
/**
* @package comments
* @subpackage tests
*/
class CommentableItem extends DataObject implements TestOnly
{
private static $db = array(
'Title' => 'Varchar'
);
private static $extensions = array(
CommentsExtension::class
);
public function RelativeLink()
{
return 'CommentableItemController';
}
public function canView($member = null)
{
return true;
}
// This is needed for canModerateComments
public function canEdit($member = null)
{
if ($member instanceof Member) {
$memberID = $member->ID;
} elseif (is_numeric($member)) {
$memberID = $member;
} else {
$memberID = Member::currentUserID();
}
if ($memberID && Permission::checkMember($memberID, array('ADMIN', 'CMS_ACCESS_CommentAdmin'))) {
return true;
}
return false;
}
public function Link()
{
return $this->RelativeLink();
}
public function AbsoluteLink()
{
return Director::absoluteURL($this->RelativeLink());
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace SilverStripe\Comments\Tests\Stubs;
use SilverStripe\Comments\Tests\Stubs\CommentableItem;
use SilverStripe\Control\Controller;
use SilverStripe\Dev\TestOnly;
/**
* @package comments
* @subpackage tests
*/
class CommentableItemController extends Controller implements TestOnly
{
public function index()
{
return CommentableItem::get()->first()->CommentsForm();
}
}

View File

@ -0,0 +1,14 @@
<?php
namespace SilverStripe\Comments\Tests\Stubs;
use SilverStripe\Comments\Tests\Stubs\CommentableItem;
class CommentableItemDisabled extends CommentableItem
{
private static $defaults = array(
'ProvideComments' => false,
'ModerationRequired' => 'None',
'CommentsRequireLogin' => false
);
}

View File

@ -0,0 +1,14 @@
<?php
namespace SilverStripe\Comments\Tests\Stubs;
use SilverStripe\Comments\Tests\Stubs\CommentableItem;
class CommentableItemEnabled extends CommentableItem
{
private static $defaults = array(
'ProvideComments' => true,
'ModerationRequired' => 'Required',
'CommentsRequireLogin' => true
);
}