SS4 compatibility updates - ORM, Form, Controller changes

* Remove CommentList and replace with a polymorphic has_one relationship
* Tweaks for unit tests. Add tests for encode/decodeClassName.
This commit is contained in:
Robbie Averill 2017-01-17 08:57:37 +13:00
parent c698632aae
commit ab3f35257b
41 changed files with 1418 additions and 1141 deletions

View File

@ -43,7 +43,7 @@ before_script:
- composer self-update || true - composer self-update || true
- git clone git://github.com/silverstripe-labs/silverstripe-travis-support.git ~/travis-support - git clone git://github.com/silverstripe-labs/silverstripe-travis-support.git ~/travis-support
# Install suggested modules in order to maximize test coverage # 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 "silverstripe/cms:^4.0@dev"
- cd ~/builds/ss - cd ~/builds/ss
script: script:

28
.upgrade.yml Normal file
View File

@ -0,0 +1,28 @@
mappings:
Commenting: SilverStripe\Comments\Commenting
CommentAdmin: SilverStripe\Comments\Admin\CommentAdmin
CommentsGridField: SilverStripe\Comments\Admin\CommentsGridField
CommentsGridFieldAction: SilverStripe\Comments\Admin\CommentsGridFieldAction
CommentsGridFieldBulkAction: SilverStripe\Comments\Admin\CommentsGridFieldBulkAction
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
CommentList: SilverStripe\Comments\Model\CommentList
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\CommentableItem
CommentableItemEnabled: SilverStripe\Comments\Tests\CommentableItemEnabled
CommentableItemDisabled: SilverStripe\Comments\Tests\CommentableItemDisabled
CommentableItem_Controller: SilverStripe\Comments\Tests\CommentableItem_Controller
CommentTestHelper: SilverStripe\Comments\Tests\CommentTestHelper

View File

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

View File

@ -4,7 +4,8 @@ After: framework/routes#coreroutes
--- ---
SilverStripe\Control\Director: SilverStripe\Control\Director:
rules: rules:
comments: SilverStripe\Comments\Controllers\CommentingController
# handle old 2.4 style urls # handle old 2.4 style urls
'CommentingController//$Action/$ID/$OtherID': 'SilverStripe\Comments\Controllers\CommentingController' CommentingController//$Action/$ID/$OtherID: SilverStripe\Comments\Controllers\CommentingController
'PageComments/$Action/$ID/$OtherID': 'SilverStripe\Comments\Controllers\CommentingController' PageComments/$Action/$ID/$OtherID: SilverStripe\Comments\Controllers\CommentingController
'PageComments_Controller/$Action/$ID/$OtherID': 'SilverStripe\Comments\Controllers\CommentingController' PageCommentsController/$Action/$ID/$OtherID: SilverStripe\Comments\Controllers\CommentingController

View File

@ -12,7 +12,6 @@
"colymba/gridfield-bulk-editing-tools": "~2.1" "colymba/gridfield-bulk-editing-tools": "~2.1"
}, },
"suggest": { "suggest": {
"ezyang/htmlpurifier": "Standards compliant HTML filter written in PHP",
"silverstripe/cms": "The SilverStripe Content Management System" "silverstripe/cms": "The SilverStripe Content Management System"
}, },
"require-dev": { "require-dev": {
@ -23,5 +22,11 @@
"dev-master": "3.x-dev" "dev-master": "3.x-dev"
} }
}, },
"autoload": {
"psr-4": {
"SilverStripe\\Comments\\": "src/",
"SilverStripe\\Comments\\Tests\\": "tests/"
}
},
"license": "BSD-3-Clause" "license": "BSD-3-Clause"
} }

View File

@ -2,16 +2,16 @@
## Overview ## 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 default settings
In order to add commenting to your site, the minimum amount of work necessary is to add the `CommentsExtension` to 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. the base class for the object which holds comments.
```yaml ```yaml
SiteTree: SilverStripe\CMS\Model\SiteTree:
extensions: extensions:
- CommentsExtension - SilverStripe\Comments\Extensions\CommentsExtension
``` ```
## Configuration ## Configuration
@ -20,9 +20,9 @@ In order to configure options for any class you should assign the specific optio
config of the specified class. config of the specified class.
```yaml ```yaml
SiteTree: SilverStripe\CMS\Model\SiteTree:
extensions: extensions:
- CommentsExtension - SilverStripe\Comments\Extensions\CommentsExtension
comments: comments:
enabled: true # Enables commenting to be disabled for a specific class (or subclass of a parent with commenting enabled) 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 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 Enabling any of the *_cms options will instead allow these options to be configured under the settings tab
of each page in the CMS. 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` the extension (or on the built-in SiteTree commenting) use `set_config_value`
```yaml ```yaml
# Set the default option for pages to require login # Set the default option for pages to require login
SiteTree: SilverStripe\CMS\Model\SiteTree:
comments: comments:
require_login: true require_login: true
``` ```
@ -71,27 +71,29 @@ SiteTree:
```php ```php
// Get the setting // Get the setting
$loginRequired = singleton('SiteTree')->getCommentsOption('require_login'); $loginRequired = singleton('SilverStripe\\CMS\\Model\\SiteTree')->getCommentsOption('require_login');
``` ```
## HTML Comments ## HTML Comments
Comments can be configured to contain a restricted set of HTML tags through the 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 `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 friendly, but combined with a rich-text editor of your own choosing it can
allow rich comment formatting. allow rich comment formatting.
In order to use this feature, you need to install the 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). through [Composer](http://getcomposer.org).
{ ```json
"require": {"ezyang/htmlpurifier": "4.*"} {
} "require": {"ezyang/htmlpurifier": "^4.8"}
}
```
**Important**: Rendering user-provided HTML on your website always risks **Important**: Rendering user-provided HTML on your website always risks
exposing your users to cross-site scripting (XSS) attacks, if the HTML isn't 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. properly sanitized. Don't allow tags like `<script>` or arbitrary attributes.
## Gravatars ## 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 Gravatars can be turned on by adding this to your mysite/_config/config.yml file
```yaml ```yaml
SiteTree: SilverStripe\CMS\Model\SiteTree:
comments: comments:
use_gravatar: true 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): omitted. To change this add the following (again to mysite/_config/config.yml):
```yaml ```yaml
SiteTree: SilverStripe\CMS\Model\SiteTree:
comments: comments:
gravatar_size: 40 gravatar_size: 40
``` ```
If the email address used to comment does not have a gravatar, it is possible 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 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 http://gravatar.com/site/implement/images/, and at the time of writing are the
following: 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. 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). (does not vary by email hash).
* identicon: a geometric pattern based on an email hash * identicon: a geometric pattern based on an email hash
* monsterid: a generated 'monster' with different colors, faces, etc * monsterid: a generated 'monster' with different colors, faces, etc
* wavatar: generated faces with differing features and backgrounds * wavatar: generated faces with differing features and backgrounds
* retro: awesome generated, 8-bit arcade-style pixelated faces * 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) purposes)
To change the default image style, add the following to mysite/_config/config.yml To change the default image style, add the following to mysite/_config/config.yml
```yaml ```yaml
SiteTree: SilverStripe\CMS\Model\SiteTree:
comments: comments:
gravatar_default: 'retro' 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 mysite/_config/config.yml
```yaml ```yaml
SiteTree: SilverStripe\CMS\Model\SiteTree:
comments: comments:
gravatar_rating: 'r' gravatar_rating: 'r'
``` ```
@ -149,8 +151,8 @@ SiteTree:
Vald values for rating are as follows: Vald values for rating are as follows:
* g: suitable for display on all websites with any audience type. * 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. 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. hard drug use.
* x: may contain hardcore sexual imagery or extremely disturbing violence. * 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 ## 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. 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. 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 <?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 * Comment administration system within the CMS
* *

View File

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

View File

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

View File

@ -1,67 +1,13 @@
<?php <?php
namespace SilverStripe\Comments\Admin;
use Colymba\BulkManager\GridFieldBulkActionHandler;
/** /**
* @package comments * @package comments
*/ */
class CommentsGridFieldBulkAction extends GridFieldBulkActionHandler class CommentsGridFieldBulkAction extends GridFieldBulkActionHandler
{ {
}
/**
* A {@link GridFieldBulkActionHandler} for bulk marking comments as spam
*
* @package comments
*/
class CommentsGridFieldBulkAction_Handlers extends CommentsGridFieldBulkAction
{
private static $allowed_actions = array(
'spam',
'approve',
);
private static $url_handlers = array(
'spam' => 'spam',
'approve' => 'approve',
);
public function spam(SS_HTTPRequest $request)
{
$ids = array();
foreach ($this->getRecords() as $record) {
array_push($ids, $record->ID);
$record->markSpam();
}
$response = new SS_HTTPResponse(Convert::raw2json(array(
'done' => true,
'records' => $ids
)));
$response->addHeader('Content-Type', 'text/json');
return $response;
}
public function approve(SS_HTTPRequest $request)
{
$ids = array();
foreach ($this->getRecords() as $record) {
array_push($ids, $record->ID);
$record->markApproved();
}
$response = new SS_HTTPResponse(Convert::raw2json(array(
'done' => true,
'records' => $ids
)));
$response->addHeader('Content-Type', 'text/json');
return $response;
}
} }

View File

@ -0,0 +1,78 @@
<?php
namespace SilverStripe\Comments\Admin\CommentsGridFieldBulkAction;
use SilverStripe\Core\Convert;
use SilverStripe\Comments\Admin\CommentsGridFieldBulkAction;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
/**
* A {@link GridFieldBulkActionHandler} for bulk marking comments as spam
*
* @package comments
*/
class Handlers extends CommentsGridFieldBulkAction
{
/**
* {@inheritDoc}
*/
private static $allowed_actions = array(
'spam',
'approve',
);
/**
* {@inheritDoc}
*/
private static $url_handlers = array(
'spam' => 'spam',
'approve' => 'approve',
);
/**
* @param HTTPRequest $request
* @return HTTPResponse
*/
public function spam(HTTPRequest $request)
{
$ids = array();
foreach ($this->getRecords() as $record) {
array_push($ids, $record->ID);
$record->markSpam();
}
$response = new HTTPResponse(Convert::raw2json(array(
'done' => true,
'records' => $ids
)));
$response->addHeader('Content-Type', 'text/json');
return $response;
}
/**
* @param HTTPRequest $request
* @return HTTPResponse
*/
public function approve(HTTPRequest $request)
{
$ids = array();
foreach ($this->getRecords() as $record) {
array_push($ids, $record->ID);
$record->markApproved();
}
$response = new HTTPResponse(Convert::raw2json(array(
'done' => true,
'records' => $ids
)));
$response->addHeader('Content-Type', 'text/json');
return $response;
}
}

View File

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

View File

@ -1,5 +1,14 @@
<?php <?php
namespace SilverStripe\Comments;
use InvalidArgumentException;
use SilverStripe\Comments\Extensions\CommentsExtension;
use SilverStripe\Core\Config\Config;
use SilverStripe\Dev\Deprecation;
use SilverStripe\Security\Member;
use SilverStripe\Security\Permission;
/** /**
* Helper Class for storing the configuration options. Retains the mapping between * Helper Class for storing the configuration options. Retains the mapping between
* objects which have comments attached and the related configuration options. * objects which have comments attached and the related configuration options.
@ -15,7 +24,6 @@
*/ */
class Commenting class Commenting
{ {
/** /**
* Adds commenting to a {@link DataObject} * Adds commenting to a {@link DataObject}
* *
@ -23,14 +31,14 @@ class Commenting
* *
* @param string classname to add commenting to * @param string classname to add commenting to
* @param array $settings Settings. See {@link self::$default_config} for * @param array $settings Settings. See {@link self::$default_config} for
* available settings * available settings
* *
* @throws InvalidArgumentException * @throws InvalidArgumentException
*/ */
public static function add($class, $settings = false) public static function add($class, $settings = false)
{ {
Deprecation::notice('2.0', 'Using Commenting::add is deprecated. Please use the config API instead'); Deprecation::notice('2.0', 'Using Commenting::add is deprecated. Please use the config API instead');
Config::inst()->update($class, 'extensions', array('CommentsExtension')); Config::inst()->update($class, 'extensions', array(CommentsExtension::class));
// Check if settings must be customised // Check if settings must be customised
if ($settings === false) { if ($settings === false) {
@ -53,7 +61,7 @@ class Commenting
public static function remove($class) public static function remove($class)
{ {
Deprecation::notice('2.0', 'Using Commenting::remove is deprecated. Please use the config API instead'); Deprecation::notice('2.0', 'Using Commenting::remove is deprecated. Please use the config API instead');
$class::remove_extension('CommentsExtension'); $class::remove_extension(CommentsExtension::class);
} }
/** /**
@ -66,7 +74,7 @@ class Commenting
public static function has_commenting($class) public static function has_commenting($class)
{ {
Deprecation::notice('2.0', 'Using Commenting::has_commenting is deprecated. Please use the config API instead'); Deprecation::notice('2.0', 'Using Commenting::has_commenting is deprecated. Please use the config API instead');
return $class::has_extension('CommentsExtension'); return $class::has_extension(CommentsExtension::class);
} }
/** /**
@ -75,16 +83,16 @@ class Commenting
* *
* @deprecated since version 2.0 * @deprecated since version 2.0
* *
* @param string $class Class to set the value on. Passing 'all' will set it to all * @param string $class Class to set the value on. Passing 'all' will set it to all
* active mappings * active mappings
* @param string $key setting to change * @param string $key setting to change
* @param mixed $value value of the setting * @param mixed $value value of the setting
*/ */
public static function set_config_value($class, $key, $value = false) 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'); Deprecation::notice('2.0', 'Commenting::set_config_value is deprecated. Use the config api instead');
if ($class === "all") { if ($class === 'all') {
$class = 'CommentsExtension'; $class = CommentsExtension::class;
} }
Config::inst()->update($class, 'comments', array($key => $value)); Config::inst()->update($class, 'comments', array($key => $value));
} }
@ -93,7 +101,7 @@ class Commenting
* Returns a given config value for a commenting class * Returns a given config value for a commenting class
* *
* @deprecated since version 2.0 * @deprecated since version 2.0
* *
* @param string $class * @param string $class
* @param string $key config value to return * @param string $key config value to return
* *
@ -110,8 +118,8 @@ class Commenting
// Get settings // Get settings
if (!$class) { if (!$class) {
$class = 'CommentsExtension'; $class = CommentsExtension::class;
} elseif (!$class::has_extension('CommentsExtension')) { } elseif (!$class::has_extension(CommentsExtension::class)) {
throw new InvalidArgumentException("$class does not have commenting enabled"); throw new InvalidArgumentException("$class does not have commenting enabled");
} }
return singleton($class)->getCommentsOption($key); return singleton($class)->getCommentsOption($key);
@ -140,7 +148,7 @@ class Commenting
* Return whether a user can post on a given commenting instance * Return whether a user can post on a given commenting instance
* *
* @deprecated since version 2.0 * @deprecated since version 2.0
* *
* @param string $class * @param string $class
* @return boolean true * @return boolean true
*/ */

View File

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

View File

@ -1,5 +1,28 @@
<?php <?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. * Extension to {@link DataObject} to enable tracking comments.
* *
@ -75,6 +98,13 @@ class CommentsExtension extends DataExtension
'CommentsRequireLogin' => 'Boolean', 'CommentsRequireLogin' => 'Boolean',
); );
/**
* {@inheritDoc}
*/
private static $has_many = [
'Commments' => 'SilverStripe\\Comments\\Model\\Comment.Parent'
];
/** /**
* CMS configurable options should default to the config values, but respect * CMS configurable options should default to the config values, but respect
* default values specified by the object * 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 * Returns the RelationList of all comments against this object. Can be used as a data source
* for a gridfield with write access. * for a gridfield with write access.
* *
* @return CommentList * @return DataList
*/ */
public function AllComments() public function AllComments()
{ {
$order = $this->owner->getCommentsOption('order_comments_by'); $order = $this->owner->getCommentsOption('order_comments_by');
$comments = CommentList::create($this->ownerBaseClass) $comments = Comment::get()
->forForeignID($this->owner->ID) ->filter('ParentID', $this->owner->ID)
->sort($order); ->sort($order);
$this->owner->extend('updateAllComments', $comments); $this->owner->extend('updateAllComments', $comments);
return $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 * 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() 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 * Returns the root level comments, with spam and unmoderated items excluded, for use in the frontend
* *
* @return CommentList * @return DataList
*/ */
public function Comments() public function Comments()
{ {
@ -414,7 +444,7 @@ class CommentsExtension extends DataExtension
*/ */
public function getCommentRSSLink() public function getCommentRSSLink()
{ {
return Controller::join_links(Director::baseURL(), 'CommentingController/rss'); return Controller::join_links(Director::baseURL(), 'comments/rss');
} }
public function getRssLinkPage() public function getRssLinkPage()
@ -431,7 +461,9 @@ class CommentsExtension extends DataExtension
public function getCommentRSSLinkPage() public function getCommentRSSLinkPage()
{ {
return Controller::join_links( return Controller::join_links(
$this->getCommentRSSLink(), $this->ownerBaseClass, $this->owner->ID $this->getCommentRSSLink(),
str_replace('\\', '-', $this->ownerBaseClass),
$this->owner->ID
); );
} }
@ -451,9 +483,9 @@ class CommentsExtension extends DataExtension
// Check if enabled // Check if enabled
$enabled = $this->getCommentsEnabled(); $enabled = $this->getCommentsEnabled();
if ($enabled && $this->owner->getCommentsOption('include_js')) { if ($enabled && $this->owner->getCommentsOption('include_js')) {
Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js'); Requirements::javascript(ADMIN_THIRDPARTY_DIR . '/jquery/jquery.js');
Requirements::javascript(THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js'); Requirements::javascript(ADMIN_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-form/jquery.form.js');
Requirements::javascript(COMMENTS_THIRDPARTY . '/jquery-validate/jquery.validate.min.js'); Requirements::javascript(COMMENTS_THIRDPARTY . '/jquery-validate/jquery.validate.min.js');
Requirements::add_i18n_javascript('comments/javascript/lang'); Requirements::add_i18n_javascript('comments/javascript/lang');
Requirements::javascript('comments/javascript/CommentsInterface.js'); Requirements::javascript('comments/javascript/CommentsInterface.js');
@ -461,7 +493,7 @@ class CommentsExtension extends DataExtension
$controller = CommentingController::create(); $controller = CommentingController::create();
$controller->setOwnerRecord($this->owner); $controller->setOwnerRecord($this->owner);
$controller->setBaseClass($this->ownerBaseClass); $controller->setParentClass($this->owner->getClassName());
$controller->setOwnerController(Controller::curr()); $controller->setOwnerController(Controller::curr());
$moderatedSubmitted = Session::get('CommentsModerated'); $moderatedSubmitted = Session::get('CommentsModerated');
@ -489,7 +521,7 @@ class CommentsExtension extends DataExtension
{ {
$class = $this->ownerBaseClass; $class = $this->ownerBaseClass;
return (is_subclass_of($class, 'SiteTree')) || ($class == 'SiteTree'); return (is_subclass_of($class, SiteTree::class)) || ($class == SiteTree::class);
} }
/** /**

View File

@ -1,5 +1,31 @@
<?php <?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. * Represents a single comment object.
* *
@ -22,40 +48,53 @@
*/ */
class Comment extends DataObject class Comment extends DataObject
{ {
/** /**
* @var array * {@inheritDoc}
*/ */
private static $db = array( private static $db = array(
'Name' => 'Varchar(200)', 'Name' => 'Varchar(200)',
'Comment' => 'Text', 'Comment' => 'Text',
'Email' => 'Varchar(200)', 'Email' => 'Varchar(200)',
'URL' => 'Varchar(255)', 'URL' => 'Varchar(255)',
'BaseClass' => 'Varchar(200)',
'Moderated' => 'Boolean(0)', 'Moderated' => 'Boolean(0)',
'IsSpam' => 'Boolean(0)', 'IsSpam' => 'Boolean(0)',
'ParentID' => 'Int',
'AllowHtml' => 'Boolean', 'AllowHtml' => 'Boolean',
'SecretToken' => 'Varchar(255)', 'SecretToken' => 'Varchar(255)',
'Depth' => 'Int', 'Depth' => 'Int'
); );
/**
* {@inheritDoc}
*/
private static $has_one = array( private static $has_one = array(
"Author" => "Member", 'Author' => Member::class,
"ParentComment" => "Comment", 'ParentComment' => self::class,
'Parent' => DataObject::class
); );
/**
* {@inheritDoc}
*/
private static $has_many = array( private static $has_many = array(
"ChildComments" => "Comment" 'ChildComments' => self::class
); );
/**
* {@inheritDoc}
*/
private static $default_sort = '"Created" DESC'; private static $default_sort = '"Created" DESC';
/**
* {@inheritDoc}
*/
private static $defaults = array( private static $defaults = array(
'Moderated' => 0, 'Moderated' => 0,
'IsSpam' => 0, 'IsSpam' => 0,
); );
/**
* {@inheritDoc}
*/
private static $casting = array( private static $casting = array(
'Title' => 'Varchar', 'Title' => 'Varchar',
'ParentTitle' => 'Varchar', 'ParentTitle' => 'Varchar',
@ -66,30 +105,46 @@ class Comment extends DataObject
'SpamLink' => 'Varchar', 'SpamLink' => 'Varchar',
'HamLink' => 'Varchar', 'HamLink' => 'Varchar',
'ApproveLink' => 'Varchar', 'ApproveLink' => 'Varchar',
'Permalink' => 'Varchar', 'Permalink' => 'Varchar'
); );
/**
* {@inheritDoc}
*/
private static $searchable_fields = array( private static $searchable_fields = array(
'Name', 'Name',
'Email', 'Email',
'Comment', 'Comment',
'Created', 'Created'
'BaseClass',
); );
/**
* {@inheritDoc}
*/
private static $summary_fields = array( private static $summary_fields = array(
'Name' => 'Submitted By', 'Name' => 'Submitted By',
'Email' => 'Email', 'Email' => 'Email',
'Comment.LimitWordCount' => 'Comment', 'Comment.LimitWordCount' => 'Comment',
'Created' => 'Date Posted', 'Created' => 'Date Posted',
'ParentTitle' => 'Post', 'Parent.Title' => 'Post',
'IsSpam' => 'Is Spam', 'IsSpam' => 'Is Spam'
); );
/**
* {@inheritDoc}
*/
private static $field_labels = array( private static $field_labels = array(
'Author' => 'Author Member', 'Author' => 'Author Member'
); );
/**
* {@inheritDoc}
*/
private static $table_name = 'Comment';
/**
* {@inheritDoc}
*/
public function onBeforeWrite() public function onBeforeWrite()
{ {
parent::onBeforeWrite(); parent::onBeforeWrite();
@ -103,6 +158,9 @@ class Comment extends DataObject
$this->updateDepth(); $this->updateDepth();
} }
/**
* {@inheritDoc}
*/
public function onBeforeDelete() public function onBeforeDelete()
{ {
parent::onBeforeDelete(); parent::onBeforeDelete();
@ -118,7 +176,7 @@ class Comment extends DataObject
*/ */
public function getSecurityToken() 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(); parent::requireDefaultRecords();
if (DB::getConn()->hasTable('PageComment')) { if (DB::get_schema()->hasTable('PageComment')) {
$comments = DB::query('SELECT * FROM "PageComment"'); $comments = DB::query('SELECT * FROM "PageComment"');
if ($comments) { if ($comments) {
@ -138,7 +196,7 @@ class Comment extends DataObject
$comment->update($pageComment); $comment->update($pageComment);
// set the variables which have changed // set the variables which have changed
$comment->BaseClass = 'SiteTree'; $comment->BaseClass = SiteTree::class;
$comment->URL = (isset($pageComment['CommenterURL'])) ? $pageComment['CommenterURL'] : ''; $comment->URL = (isset($pageComment['CommenterURL'])) ? $pageComment['CommenterURL'] : '';
if ((int) $pageComment['NeedsModeration'] == 0) { if ((int) $pageComment['NeedsModeration'] == 0) {
$comment->Moderated = true; $comment->Moderated = true;
@ -149,7 +207,7 @@ class Comment extends DataObject
} }
DB::alteration_message('Migrated PageComment to Comment', 'changed'); 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 = '') public function Link($action = '')
{ {
if ($parent = $this->getParent()) { if ($parent = $this->Parent()) {
return $parent->Link($action) . '#' . $this->Permalink(); return $parent->Link($action) . '#' . $this->Permalink();
} }
} }
@ -212,22 +270,25 @@ class Comment extends DataObject
public function getOption($key) public function getOption($key)
{ {
// If possible use the current record // 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 // Otherwise a singleton of that record
$record = singleton($this->BaseClass); $record = singleton($this->Parent()->dataClass());
} elseif (!$record) { } elseif (!$record) {
// Otherwise just use the default options // 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 * Returns the parent {@link DataObject} this comment is attached too
* *
* @deprecated 4.0.0 Use $this->Parent() instead
* @return DataObject * @return DataObject
*/ */
public function getParent() public function getParent()
@ -245,7 +306,7 @@ class Comment extends DataObject
*/ */
public function getParentTitle() public function getParentTitle()
{ {
if ($parent = $this->getParent()) { if ($parent = $this->Parent()) {
return $parent->Title ?: ($parent->ClassName . ' #' . $parent->ID); return $parent->Title ?: ($parent->ClassName . ' #' . $parent->ID);
} }
} }
@ -257,13 +318,16 @@ class Comment extends DataObject
*/ */
public function getParentClassName() public function getParentClassName()
{ {
return $this->BaseClass; return $this->Parent()->getClassName();
} }
/**
* {@inheritDoc}
*/
public function castingHelper($field) public function castingHelper($field)
{ {
// Safely escape the comment // Safely escape the comment
if ($field === 'EscapedComment') { if (in_array($field, ['EscapedComment', 'Comment'], true)) {
return $this->AllowHtml ? 'HTMLText' : 'Text'; return $this->AllowHtml ? 'HTMLText' : 'Text';
} }
return parent::castingHelper($field); return parent::castingHelper($field);
@ -293,10 +357,10 @@ class Comment extends DataObject
* @todo needs to compare to the new {@link Commenting} configuration API * @todo needs to compare to the new {@link Commenting} configuration API
* *
* @param Member $member * @param Member $member
* * @param array $context
* @return bool * @return bool
*/ */
public function canCreate($member = null) public function canCreate($member = null, $context = [])
{ {
return false; return false;
} }
@ -306,7 +370,6 @@ class Comment extends DataObject
* flag being set to true. * flag being set to true.
* *
* @param Member $member * @param Member $member
*
* @return Boolean * @return Boolean
*/ */
public function canView($member = null) public function canView($member = null)
@ -322,9 +385,9 @@ class Comment extends DataObject
return true; return true;
} }
if ($parent = $this->getParent()) { if ($parent = $this->Parent()) {
return $parent->canView($member) return $parent->canView($member)
&& $parent->has_extension('CommentsExtension') && $parent->hasExtension(CommentsExtension::class)
&& $parent->CommentsEnabled; && $parent->CommentsEnabled;
} }
@ -335,7 +398,6 @@ class Comment extends DataObject
* Checks if the comment can be edited. * Checks if the comment can be edited.
* *
* @param null|int|Member $member * @param null|int|Member $member
*
* @return Boolean * @return Boolean
*/ */
public function canEdit($member = null) public function canEdit($member = null)
@ -355,7 +417,7 @@ class Comment extends DataObject
return true; return true;
} }
if ($parent = $this->getParent()) { if ($parent = $this->Parent()) {
return $parent->canEdit($member); return $parent->canEdit($member);
} }
@ -366,7 +428,6 @@ class Comment extends DataObject
* Checks if the comment can be deleted. * Checks if the comment can be deleted.
* *
* @param null|int|Member $member * @param null|int|Member $member
*
* @return Boolean * @return Boolean
*/ */
public function canDelete($member = null) public function canDelete($member = null)
@ -398,7 +459,7 @@ class Comment extends DataObject
} }
if (is_numeric($member)) { if (is_numeric($member)) {
$member = DataObject::get_by_id('Member', $member, true); $member = DataObject::get_by_id(Member::class, $member, true);
} }
return $member; return $member;
@ -435,9 +496,17 @@ class Comment extends DataObject
return false; 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( $url = Controller::join_links(
Director::baseURL(), Director::baseURL(),
'CommentingController', 'comments',
$action, $action,
$this->ID $this->ID
); );
@ -556,7 +625,7 @@ class Comment extends DataObject
{ {
$title = sprintf(_t('Comment.COMMENTBY', 'Comment by %s', 'Name'), $this->getAuthorName()); $title = sprintf(_t('Comment.COMMENTBY', 'Comment by %s', 'Name'), $this->getAuthorName());
if ($parent = $this->getParent()) { if ($parent = $this->Parent()) {
if ($parent->Title) { if ($parent->Title) {
$title .= sprintf(' %s %s', _t('Comment.ON', 'on'), $parent->Title); $title .= sprintf(' %s %s', _t('Comment.ON', 'on'), $parent->Title);
} }
@ -570,7 +639,7 @@ class Comment extends DataObject
*/ */
public function getCMSFields() public function getCMSFields()
{ {
$commentField = $this->AllowHtml ? 'HtmlEditorField' : 'TextareaField'; $commentField = $this->AllowHtml ? HTMLEditorField::class : TextareaField::class;
$fields = new FieldList( $fields = new FieldList(
$this $this
->obj('Created') ->obj('Created')
@ -610,8 +679,8 @@ class Comment extends DataObject
// FIXME - the method setName in DatetimeField is not chainable, hence // FIXME - the method setName in DatetimeField is not chainable, hence
// the lack of chaining here // the lack of chaining here
$createdField = $parent $createdField = $parent
->obj('Created') ->obj('Created')
->scaffoldFormField($parent->fieldLabel('Created')); ->scaffoldFormField($parent->fieldLabel('Created'));
$createdField->setName('ParentComment_Created'); $createdField->setName('ParentComment_Created');
$createdField->setValue($parent->Created); $createdField->setValue($parent->Created);
$createdField->performReadonlyTransformation(); $createdField->performReadonlyTransformation();
@ -631,7 +700,7 @@ class Comment extends DataObject
$fields->push( $fields->push(
$parent $parent
->obj('EscapedComment') ->obj('EscapedComment')
->scaffoldFormField($parent->fieldLabel('Comment')) ->scaffoldFormField($parent->fieldLabel(self::class))
->setName('ParentComment_EscapedComment') ->setName('ParentComment_EscapedComment')
->setValue($parent->Comment) ->setValue($parent->Comment)
->performReadonlyTransformation() ->performReadonlyTransformation()
@ -643,9 +712,9 @@ class Comment extends DataObject
} }
/** /**
* @param String $dirtyHtml * @param string $dirtyHtml
* *
* @return String * @return string
*/ */
public function purifyHtml($dirtyHtml) public function purifyHtml($dirtyHtml)
{ {
@ -659,8 +728,10 @@ class Comment extends DataObject
public function getHtmlPurifierService() public function getHtmlPurifierService()
{ {
$config = HTMLPurifier_Config::createDefault(); $config = HTMLPurifier_Config::createDefault();
$allowedElements = $this->getOption('html_allowed_elements'); $allowedElements = (array) $this->getOption('html_allowed_elements');
$config->set('HTML.AllowedElements', $allowedElements); if (!empty($allowedElements)) {
$config->set('HTML.AllowedElements', $allowedElements);
}
// This injector cannot be set unless the 'p' element is allowed // This injector cannot be set unless the 'p' element is allowed
if (in_array('p', $allowedElements)) { if (in_array('p', $allowedElements)) {
@ -748,7 +819,7 @@ class Comment extends DataObject
$list = $this->AllReplies(); $list = $this->AllReplies();
// Filter spam comments for non-administrators if configured // Filter spam comments for non-administrators if configured
$parent = $this->getParent(); $parent = $this->Parent();
$showSpam = $this->getOption('frontend_spam') && $parent && $parent->canModerateComments(); $showSpam = $this->getOption('frontend_spam') && $parent && $parent->canModerateComments();
if (!$showSpam) { if (!$showSpam) {
$list = $list->filter('IsSpam', 0); $list = $list->filter('IsSpam', 0);
@ -778,7 +849,7 @@ class Comment extends DataObject
// Add pagination // Add pagination
$list = new PaginatedList($list, Controller::curr()->getRequest()); $list = new PaginatedList($list, Controller::curr()->getRequest());
$list->setPaginationGetVar('repliesstart'.$this->ID); $list->setPaginationGetVar('repliesstart' . $this->ID);
$list->setPageLength($this->getOption('comments_per_page')); $list->setPageLength($this->getOption('comments_per_page'));
$this->extend('updatePagedReplies', $list); $this->extend('updatePagedReplies', $list);
@ -798,7 +869,7 @@ class Comment extends DataObject
} }
// Check parent is available // Check parent is available
$parent = $this->getParent(); $parent = $this->Parent();
if (!$parent || !$parent->exists()) { if (!$parent || !$parent->exists()) {
return null; return null;
} }
@ -806,7 +877,7 @@ class Comment extends DataObject
// Build reply controller // Build reply controller
$controller = CommentingController::create(); $controller = CommentingController::create();
$controller->setOwnerRecord($parent); $controller->setOwnerRecord($parent);
$controller->setBaseClass($parent->ClassName); $controller->setParentClass($parent->ClassName);
$controller->setOwnerController(Controller::curr()); $controller->setOwnerController(Controller::curr());
return $controller->ReplyForm($this); 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

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

@ -0,0 +1,47 @@
<?php
namespace SilverStripe\Comments\Tasks;
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
{
/**
* {@inheritDoc}
*/
private static $segment = 'MigrateCommentParentsTask';
/**
* {@inheritDoc}
*/
protected $title = 'Migrate Comment Parent classes from 3.x';
/**
* {@inheritDoc}
*/
protected $description = 'Migrates all 3.x Comment BaseClass fields to the new ParentClass fields in 4.0';
/**
* {@inheritDoc}
*/
public function run($request)
{
// 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 %> <% end_if %>
$AddCommentForm $AddCommentForm
<% else %> <% 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>. <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> </p>
<% end_if %> <% 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> <a href="$DeleteLink.ATT" class="delete"><% _t('CommentsInterface_singlecomment_ss.REMCOM','reject it') %></a>
<% end_if %> <% end_if %>
</div> </div>
<% if $RepliesEnabled %> <% if $RepliesEnabled && $canPostComment %>
<a class="comment-reply-link" href="#{$ReplyForm.FormName}"><% _t('CommentsInterface_singlecomment_ss.REPLYTO','Reply to') %> $AuthorName.XML</a> <a class="comment-reply-link" href="#{$ReplyForm.FormName}"><% _t('CommentsInterface_singlecomment_ss.REPLYTO','Reply to') %> $AuthorName.XML</a>
<% end_if %> <% end_if %>
</div> </div>

View File

@ -1,10 +1,19 @@
<?php <?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 class CommentAdminTest extends SapphireTest
{ {
/**
* {@inheritDoc}
*/
protected $usesDatabase = true; protected $usesDatabase = true;
public function testProvidePermissions() public function testProvidePermissions()
{ {
$commentAdmin = new CommentAdmin(); $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 <?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 * 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 * field group inside of a Root.Settings tab will not work
*/ */
public static function assertFieldsForTab($context, $tabName, $expected, $fields) public static function assertFieldsForTab($context, $tabName, $expected, $fields)
{ {
$tab = $fields->findOrMakeTab($tabName); $tab = $fields->findOrMakeTab($tabName);
$fields = $tab->FieldList(); $fields = $tab->FieldList();
CommentTestHelper::assertFieldNames($context, $expected, $fields); self::assertFieldNames($context, $expected, $fields);
} }
public static function assertFieldNames($context, $expected, $fields) public static function assertFieldNames($context, $expected, $fields)
{ {
$actual = array(); $actual = array();
foreach ($fields as $field) { foreach ($fields as $field) {
if (get_class($field) == 'FieldGroup') { array_push($actual, $field->getName());
array_push($actual, $field->Name());
} else {
array_push($actual, $field->getName());
}
} }
$context->assertEquals($expected, $actual); $context->assertEquals($expected, $actual);
} }

View File

@ -1,16 +1,36 @@
<?php <?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 * @package comments
* @subpackage tests * @subpackage tests
*/ */
class CommentingControllerTest extends FunctionalTest class CommentingControllerTest extends FunctionalTest
{ {
/**
* {@inheritDoc}
*/
public static $fixture_file = 'CommentsTest.yml'; public static $fixture_file = 'CommentsTest.yml';
/**
* {@inheritDoc}
*/
protected $extraDataObjects = array( protected $extraDataObjects = array(
'CommentableItem' CommentableItem::class
); );
protected $securityEnabled; protected $securityEnabled;
@ -18,9 +38,9 @@ class CommentingControllerTest extends FunctionalTest
public function tearDown() public function tearDown()
{ {
if ($this->securityEnabled) { if ($this->securityEnabled) {
SecurityToken::enable(); SecurityToken::inst()->enable();
} else { } else {
SecurityToken::disable(); SecurityToken::inst()->disable();
} }
parent::tearDown(); parent::tearDown();
} }
@ -28,30 +48,32 @@ class CommentingControllerTest extends FunctionalTest
public function setUp() public function setUp()
{ {
parent::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 // mark a comment as spam then approve it
$this->logInWithPermission('CMS_ACCESS_CommentAdmin'); $this->logInWithPermission('CMS_ACCESS_CommentAdmin');
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'testModeratedComment1');
$comment->markSpam(); $st = new CommentSecurityToken($comment);
$st = new Comment_SecurityToken($comment); $url = 'comments/approve/' . $comment->ID;
$url = 'CommentingController/approve/' . $comment->ID;
$url = $st->addToUrl($url, Member::currentUser()); $url = $st->addToUrl($url, Member::currentUser());
$response = $this->get($url); $response = $this->get($url, null, ['Referer' => '/']);
$this->assertEquals(200, $response->getStatusCode()); $this->assertEquals(302, $response->getStatusCode());
$comment = DataObject::get_by_id('Comment', $comment->ID); $comment = DataObject::get_by_id(Comment::class, $comment->ID);
// Need to use 0,1 here instead of false, true for SQLite // Need to use 0,1 here instead of false, true for SQLite
$this->assertEquals(0, $comment->IsSpam); $this->assertEquals(0, $comment->IsSpam);
$this->assertEquals(1, $comment->Moderated); $this->assertEquals(1, $comment->Moderated);
// try and approve a non existent comment // try and approve a non existent comment
$response = $this->get('CommentingController/approve/100000'); $response = $this->get('comments/approve/100000');
$this->assertEquals(404, $response->getStatusCode()); $this->assertEquals(404, $response->getStatusCode());
} }
@ -66,25 +88,25 @@ class CommentingControllerTest extends FunctionalTest
public function testHam() public function testHam()
{ {
SecurityToken::disable(); SecurityToken::inst()->disable();
// mark a comment as spam then ham it // mark a comment as spam then ham it
$this->logInWithPermission('CMS_ACCESS_CommentAdmin'); $this->logInWithPermission('CMS_ACCESS_CommentAdmin');
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$comment->markSpam(); $comment->markSpam();
$st = new Comment_SecurityToken($comment); $st = new CommentSecurityToken($comment);
$url = 'CommentingController/ham/' . $comment->ID; $url = 'comments/ham/' . $comment->ID;
$url = $st->addToUrl($url, Member::currentUser()); $url = $st->addToUrl($url, Member::currentUser());
$response = $this->get($url); $response = $this->get($url);
$this->assertEquals(200, $response->getStatusCode()); $this->assertEquals(302, $response->getStatusCode());
$comment = DataObject::get_by_id('Comment', $comment->ID); $comment = DataObject::get_by_id(Comment::class, $comment->ID);
// Need to use 0,1 here instead of false, true for SQLite // Need to use 0,1 here instead of false, true for SQLite
$this->assertEquals(0, $comment->IsSpam); $this->assertEquals(0, $comment->IsSpam);
$this->assertEquals(1, $comment->Moderated); $this->assertEquals(1, $comment->Moderated);
// try and ham a non existent comment // try and ham a non existent comment
$response = $this->get('CommentingController/ham/100000'); $response = $this->get('comments/ham/100000');
$this->assertEquals(404, $response->getStatusCode()); $this->assertEquals(404, $response->getStatusCode());
} }
@ -92,55 +114,54 @@ class CommentingControllerTest extends FunctionalTest
{ {
// mark a comment as approved then spam it // mark a comment as approved then spam it
$this->logInWithPermission('CMS_ACCESS_CommentAdmin'); $this->logInWithPermission('CMS_ACCESS_CommentAdmin');
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$comment->markApproved(); $comment->markApproved();
$st = new Comment_SecurityToken($comment); $st = new CommentSecurityToken($comment);
$url = 'CommentingController/spam/' . $comment->ID; $url = 'comments/spam/' . $comment->ID;
$url = $st->addToUrl($url, Member::currentUser()); $url = $st->addToUrl($url, Member::currentUser());
$response = $this->get($url); $response = $this->get($url);
$this->assertEquals(200, $response->getStatusCode()); $this->assertEquals(302, $response->getStatusCode());
$comment = DataObject::get_by_id('Comment', $comment->ID); $comment = DataObject::get_by_id(Comment::class, $comment->ID);
// Need to use 0,1 here instead of false, true for SQLite // Need to use 0,1 here instead of false, true for SQLite
$this->assertEquals(1, $comment->IsSpam); $this->assertEquals(1, $comment->IsSpam);
$this->assertEquals(1, $comment->Moderated); $this->assertEquals(1, $comment->Moderated);
// try and spam a non existent comment // try and spam a non existent comment
$response = $this->get('CommentingController/spam/100000'); $response = $this->get('comments/spam/100000');
$this->assertEquals(404, $response->getStatusCode()); $this->assertEquals(404, $response->getStatusCode());
} }
public function testRSS() public function testRSS()
{ {
// Delete the newly added children of firstComA so as not to have to recalculate values below // Delete the newly added children of firstComA so as not to have to recalculate values below
$this->objFromFixture('Comment', 'firstComAChild1')->delete(); $this->objFromFixture(Comment::class, 'firstComAChild1')->delete();
$this->objFromFixture('Comment', 'firstComAChild2')->delete(); $this->objFromFixture(Comment::class, 'firstComAChild2')->delete();
$this->objFromFixture('Comment', 'firstComAChild3')->delete(); $this->objFromFixture(Comment::class, 'firstComAChild3')->delete();
$item = $this->objFromFixture('CommentableItem', 'first');
$item = $this->objFromFixture(CommentableItem::class, 'first');
// comments sitewide // 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"); $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"); $this->assertEquals(4, substr_count($response->getBody(), "<item>"), "3 approved, non spam comments on page 2");
// all comments on a type // 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>")); $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"); $this->assertEquals(4, substr_count($response->getBody(), "<item>"), "3 approved, non spam comments on page 2");
// specific page // 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->assertEquals(1, substr_count($response->getBody(), "<item>"));
$this->assertContains('<dc:creator>FA</dc:creator>', $response->getBody()); $this->assertContains('<dc:creator>FA</dc:creator>', $response->getBody());
// test accessing comments on a type that doesn't exist // 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()); $this->assertEquals(404, $response->getStatusCode());
} }
@ -151,8 +172,8 @@ class CommentingControllerTest extends FunctionalTest
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture('Comment', 'firstComA');
$item = $this->objFromFixture('CommentableItem', 'first'); $item = $this->objFromFixture('CommentableItem', 'first');
$st = new Comment_SecurityToken($comment); $st = new CommentSecurityToken($comment);
$url = 'CommentingController/reply/' . $item->ID.'?ParentCommentID=' . $comment->ID; $url = 'comments/reply/' . $item->ID.'?ParentCommentID=' . $comment->ID;
error_log($url); error_log($url);
$response = $this->get($url); $response = $this->get($url);
error_log(print_r($response,1)); error_log(print_r($response,1));
@ -167,7 +188,7 @@ class CommentingControllerTest extends FunctionalTest
'use_preview' => false 'use_preview' => false
)); ));
$this->logInAs('visitor'); $this->logInAs('visitor');
SecurityToken::disable(); SecurityToken::inst()->disable();
$parent = $this->objFromFixture('CommentableItem', 'first'); $parent = $this->objFromFixture('CommentableItem', 'first');
$parent->CommentsRequireLogin = true; $parent->CommentsRequireLogin = true;
$parent->PostingRequiredPermission = true; $parent->PostingRequiredPermission = true;
@ -185,17 +206,17 @@ class CommentingControllerTest extends FunctionalTest
public function testCommentsFormUsePreview() public function testCommentsFormUsePreview()
{ {
// test with preview on // test with preview on
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'use_preview' => true 'use_preview' => true
)); ));
$this->objFromFixture('Comment', 'firstComAChild1')->delete(); $this->objFromFixture(Comment::class, 'firstComAChild1')->delete();
$this->objFromFixture('Comment', 'firstComAChild2')->delete(); $this->objFromFixture(Comment::class, 'firstComAChild2')->delete();
$this->objFromFixture('Comment', 'firstComAChild3')->delete(); $this->objFromFixture(Comment::class, 'firstComAChild3')->delete();
SecurityToken::disable(); SecurityToken::inst()->disable();
$this->autoFollowRedirection = false; $this->autoFollowRedirection = false;
$parent = $this->objFromFixture('CommentableItem', 'first'); $parent = $this->objFromFixture(CommentableItem::class, 'first');
$commController = new CommentingController(); $commController = new CommentingController();
$commController->setOwnerRecord($parent); $commController->setOwnerRecord($parent);
@ -205,7 +226,7 @@ class CommentingControllerTest extends FunctionalTest
CommentTestHelper::assertFieldNames($this, $expected, $commentsFields); CommentTestHelper::assertFieldNames($this, $expected, $commentsFields);
// Turn off preview. Assert lack of preview field // Turn off preview. Assert lack of preview field
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'use_preview' => false 'use_preview' => false
)); ));
$form = $commController->CommentsForm(); $form = $commController->CommentsForm();
@ -216,64 +237,89 @@ class CommentingControllerTest extends FunctionalTest
public function testCommentsForm() public function testCommentsForm()
{ {
// Delete the newly added children of firstComA so as not to change this test $this->autoFollowRedirection = true;
$this->objFromFixture('Comment', 'firstComAChild1')->delete();
$this->objFromFixture('Comment', 'firstComAChild2')->delete();
$this->objFromFixture('Comment', 'firstComAChild3')->delete();
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; $this->autoFollowRedirection = false;
$parent = $this->objFromFixture('CommentableItem', 'first'); $parent = $this->objFromFixture(CommentableItem::class, 'first');
// Test posting to base comment // Test posting to base comment
$response = $this->post('CommentingController/CommentsForm', $response = $this->post(
'comments/CommentsForm',
array( array(
'Name' => 'Poster', 'Name' => 'Poster',
'Email' => 'guy@test.com', 'Email' => 'guy@test.com',
'Comment' => 'My Comment', 'Comment' => 'My Comment',
'ParentID' => $parent->ID, 'ParentID' => $parent->ID,
'BaseClass' => 'CommentableItem', 'ParentClassName' => CommentableItem::class,
'action_doPostComment' => 'Post' 'action_doPostComment' => 'Post'
) )
); );
$this->assertEquals(302, $response->getStatusCode()); $this->assertEquals(302, $response->getStatusCode());
$this->assertStringStartsWith('CommentableItem_Controller#comment-', $response->getHeader('Location')); // $this->assertStringStartsWith('CommentableItemController#comment-', $response->getHeader('Location'));
$this->assertDOSEquals( $this->assertDOSEquals(
array(array( array(
'Name' => 'Poster', array(
'Email' => 'guy@test.com', 'Name' => 'Poster',
'Comment' => 'My Comment', 'Email' => 'guy@test.com',
'ParentID' => $parent->ID, 'Comment' => 'My Comment',
'BaseClass' => 'CommentableItem', 'ParentID' => $parent->ID,
)), 'ParentClass' => CommentableItem::class,
)
),
Comment::get()->filter('Email', 'guy@test.com') Comment::get()->filter('Email', 'guy@test.com')
); );
// Test posting to parent comment // Test posting to parent comment
$parentComment = $this->objFromFixture('Comment', 'firstComA'); $parentComment = $this->objFromFixture(Comment::class, 'firstComA');
$this->assertEquals(0, $parentComment->ChildComments()->count()); $this->assertEquals(0, $parentComment->ChildComments()->count());
$response = $this->post( $response = $this->post(
'CommentingController/reply/'.$parentComment->ID, 'comments/reply/' . $parentComment->ID,
array( array(
'Name' => 'Test Author', 'Name' => 'Test Author',
'Email' => 'test@test.com', 'Email' => 'test@test.com',
'Comment' => 'Making a reply to firstComA', 'Comment' => 'Making a reply to firstComA',
'ParentID' => $parent->ID, 'ParentID' => $parent->ID,
'BaseClass' => 'CommentableItem', 'ParentClassName' => CommentableItem::class,
'ParentCommentID' => $parentComment->ID, 'ParentCommentID' => $parentComment->ID,
'action_doPostComment' => 'Post' 'action_doPostComment' => 'Post'
) )
); );
$this->assertEquals(302, $response->getStatusCode()); $this->assertEquals(302, $response->getStatusCode());
$this->assertStringStartsWith('CommentableItem_Controller#comment-', $response->getHeader('Location')); // $this->assertStringStartsWith('CommentableItemController#comment-', $response->getHeader('Location'));
$this->assertDOSEquals(array(array( $this->assertDOSEquals(
'Name' => 'Test Author', array(
'Email' => 'test@test.com', array(
'Comment' => 'Making a reply to firstComA', 'Name' => 'Test Author',
'ParentID' => $parent->ID, 'Email' => 'test@test.com',
'BaseClass' => 'CommentableItem', 'Comment' => 'Making a reply to firstComA',
'ParentCommentID' => $parentComment->ID 'ParentID' => $parent->ID,
)), $parentComment->ChildComments()); '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,8 +1,17 @@
<?php <?php
namespace SilverStripe\Comments\Tests;
use PHPUnit_Framework_Error_Deprecated;
use SilverStripe\Comments\Commenting;
use SilverStripe\Comments\Extensions\CommentsExtension;
use SilverStripe\Comments\Tests\Stubs\CommentableItem;
use SilverStripe\Core\Config\Config;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Security\Member;
class CommentingTest extends SapphireTest class CommentingTest extends SapphireTest
{ {
public function setUpOnce() public function setUpOnce()
{ {
parent::setUpOnce(); parent::setUpOnce();
@ -13,7 +22,7 @@ class CommentingTest extends SapphireTest
$methods = array('add', 'remove', 'has_commenting'); $methods = array('add', 'remove', 'has_commenting');
foreach ($methods as $methodName) { foreach ($methods as $methodName) {
try { try {
Commenting::$methodName('Member'); Commenting::$methodName(Member::class);
} catch (PHPUnit_Framework_Error_Deprecated $e) { } catch (PHPUnit_Framework_Error_Deprecated $e) {
$expected = 'Using Commenting:' . $methodName .' is deprecated.' $expected = 'Using Commenting:' . $methodName .' is deprecated.'
. ' Please use the config API instead'; . ' Please use the config API instead';
@ -22,18 +31,17 @@ class CommentingTest extends SapphireTest
} }
} }
public function testSetConfigValue()
public function test_set_config_value()
{ {
// public static function set_config_value($class, $key, $value = false) { // public static function set_config_value($class, $key, $value = false) {
Commenting::set_config_value( Commenting::set_config_value(
'CommentableItem', CommentableItem::class,
'comments_holder_id', 'comments_holder_id',
'commentable_item' 'commentable_item'
); );
$config = Config::inst()->get( $config = Config::inst()->get(
'CommentableItem', CommentableItem::class,
'comments' 'comments'
); );
$actual = $config['comments_holder_id']; $actual = $config['comments_holder_id'];
@ -49,7 +57,7 @@ class CommentingTest extends SapphireTest
); );
$config = Config::inst()->get( $config = Config::inst()->get(
'CommentsExtension', CommentsExtension::class,
'comments' 'comments'
); );
$actual = $config['comments_holder_id']; $actual = $config['comments_holder_id'];
@ -59,19 +67,23 @@ class CommentingTest extends SapphireTest
); );
} }
public function test_get_config_value() public function testGetConfigValue()
{ {
Config::inst()->update('CommentableItem', 'comments', Config::inst()->update(
CommentableItem::class,
'comments',
array( array(
'comments_holder_id' => 'commentable_item' 'comments_holder_id' => 'commentable_item'
) )
); );
$this->assertEquals( $this->assertEquals(
'commentable_item', 'commentable_item',
Commenting::get_config_value('CommentableItem', 'comments_holder_id') Commenting::get_config_value(CommentableItem::class, 'comments_holder_id')
); );
Config::inst()->update('CommentsExtension', 'comments', Config::inst()->update(
CommentsExtension::class,
'comments',
array( array(
'comments_holder_id' => 'comments_extension' 'comments_holder_id' => 'comments_extension'
) )
@ -86,12 +98,14 @@ class CommentingTest extends SapphireTest
'InvalidArgumentException', 'InvalidArgumentException',
'Member does not have commenting enabled' 'Member does not have commenting enabled'
); );
Commenting::get_config_value('Member', 'comments_holder_id'); Commenting::get_config_value(Member::class, 'comments_holder_id');
} }
public function test_config_value_equals() public function testConfigValueEquals()
{ {
Config::inst()->update('CommentableItem', 'comments', Config::inst()->update(
CommentableItem::class,
'comments',
array( array(
'comments_holder_id' => 'some_value' 'comments_holder_id' => 'some_value'
) )
@ -99,7 +113,7 @@ class CommentingTest extends SapphireTest
$this->assertTrue( $this->assertTrue(
Commenting::config_value_equals( Commenting::config_value_equals(
'CommentableItem', CommentableItem::class,
'comments_holder_id', 'comments_holder_id',
'some_value' 'some_value'
) )
@ -107,33 +121,33 @@ class CommentingTest extends SapphireTest
$this->assertNull( $this->assertNull(
Commenting::config_value_equals( Commenting::config_value_equals(
'CommentableItem', CommentableItem::class,
'comments_holder_id', 'comments_holder_id',
'not_some_value' 'not_some_value'
) )
); );
} }
public function test_add() public function testAdd()
{ {
Commenting::add('Member', array('comments_holder_id' => 'test_add_value')); Commenting::add(Member::class, array('comments_holder_id' => 'test_add_value'));
$config = Config::inst()->get( $config = Config::inst()->get(
'Member', Member::class,
'comments' 'comments'
); );
$actual = $config['comments_holder_id']; $actual = $config['comments_holder_id'];
$this->assertEquals( $this->assertEquals(
'test_add_value', 'test_add_value',
$actual $actual
); );
Commenting::add('Member'); Commenting::add(Member::class);
$config = Config::inst()->get( $config = Config::inst()->get(
'Member', Member::class,
'comments' 'comments'
); );
$actual = $config['comments_holder_id']; $actual = $config['comments_holder_id'];
// no settings updated // no settings updated
$this->assertEquals( $this->assertEquals(
@ -142,39 +156,45 @@ class CommentingTest extends SapphireTest
); );
$this->setExpectedException('InvalidArgumentException', "\$settings needs to be an array or null"); $this->setExpectedException('InvalidArgumentException', "\$settings needs to be an array or null");
Commenting::add('Member', 'illegal format, not an array'); Commenting::add(Member::class, 'illegal format, not an array');
} }
public function test_can_member_post() public function testCanMemberPost()
{ {
// logout // logout
if ($member = Member::currentUser()) { if ($member = Member::currentUser()) {
$member->logOut(); $member->logOut();
} }
Config::inst()->update('CommentableItem', 'comments', Config::inst()->update(
CommentableItem::class,
'comments',
array( array(
'require_login' => false 'require_login' => false
) )
); );
$this->assertTrue(Commenting::can_member_post('CommentableItem')); $this->assertTrue(Commenting::can_member_post(CommentableItem::class));
Config::inst()->update('CommentableItem', 'comments', Config::inst()->update(
CommentableItem::class,
'comments',
array( array(
'require_login' => true 'require_login' => true
) )
); );
$this->assertFalse(Commenting::can_member_post('CommentableItem')); $this->assertFalse(Commenting::can_member_post(CommentableItem::class));
$this->logInWithPermission('CMS_ACCESS_CommentAdmin'); $this->logInWithPermission('CMS_ACCESS_CommentAdmin');
$this->assertTrue(Commenting::can_member_post('CommentableItem')); $this->assertTrue(Commenting::can_member_post(CommentableItem::class));
Config::inst()->update('CommentableItem', 'comments', Config::inst()->update(
CommentableItem::class,
'comments',
array( array(
'require_login' => false 'require_login' => false
) )
); );
$this->assertTrue(Commenting::can_member_post('CommentableItem')); $this->assertTrue(Commenting::can_member_post(CommentableItem::class));
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -1,17 +1,24 @@
<?php <?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 class CommentsGridFieldTest extends SapphireTest
{ {
public function testNewRow() public function testNewRow()
{ {
$gridfield = new CommentsGridField('testfield', 'testfield'); $gridfield = new CommentsGridField('testfield', 'testfield');
// protected function newRow($total, $index, $record, $attributes, $content) { // protected function newRow($total, $index, $record, $attributes, $content) {
$comment = new Comment(); $comment = new Comment();
$comment->Name = 'Fred Bloggs'; $comment->Name = 'Fred Bloggs';
$comment->Comment = 'This is a comment'; $comment->Comment = 'This is a comment';
$attr = array(); $attr = array();
try { try {
$class = new ReflectionClass($gridfield); $class = new ReflectionClass($gridfield);
$method = $class->getMethod('newRow'); $method = $class->getMethod('newRow');

View File

@ -1,17 +1,41 @@
<?php <?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 * @package comments
*/ */
class CommentsTest extends FunctionalTest class CommentsTest extends FunctionalTest
{ {
/**
* {@inheritDoc}
*/
public static $fixture_file = 'comments/tests/CommentsTest.yml'; public static $fixture_file = 'comments/tests/CommentsTest.yml';
/**
* {@inheritDoc}
*/
protected $extraDataObjects = array( protected $extraDataObjects = array(
'CommentableItem', CommentableItem::class,
'CommentableItemEnabled', CommentableItemEnabled::class,
'CommentableItemDisabled' CommentableItemDisabled::class
); );
public function setUp() public function setUp()
@ -20,7 +44,7 @@ class CommentsTest extends FunctionalTest
Config::nest(); Config::nest();
// Set good default values // Set good default values
Config::inst()->update('CommentsExtension', 'comments', array( Config::inst()->update(CommentsExtension::class, 'comments', array(
'enabled' => true, 'enabled' => true,
'enabled_cms' => false, 'enabled_cms' => false,
'require_login' => false, 'require_login' => false,
@ -34,7 +58,7 @@ class CommentsTest extends FunctionalTest
)); ));
// Configure this dataobject // Configure this dataobject
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'enabled_cms' => true 'enabled_cms' => true
)); ));
} }
@ -49,13 +73,13 @@ class CommentsTest extends FunctionalTest
{ {
// comments don't require moderation so unmoderated comments can be // comments don't require moderation so unmoderated comments can be
// shown but not spam posts // shown but not spam posts
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'require_moderation_nonmembers' => false, 'require_moderation_nonmembers' => false,
'require_moderation' => false, 'require_moderation' => false,
'require_moderation_cms' => false, 'require_moderation_cms' => false,
)); ));
$item = $this->objFromFixture('CommentableItem', 'spammed'); $item = $this->objFromFixture(CommentableItem::class, 'spammed');
$this->assertEquals('None', $item->ModerationRequired); $this->assertEquals('None', $item->ModerationRequired);
$this->assertDOSEquals(array( $this->assertDOSEquals(array(
@ -64,11 +88,11 @@ class CommentsTest extends FunctionalTest
), $item->Comments(), 'Only 2 non spam posts should be shown'); ), $item->Comments(), 'Only 2 non spam posts should be shown');
// when moderated, only moderated, 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); $this->assertEquals('NonMembersOnly', $item->ModerationRequired);
// Check that require_moderation overrides this option // 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->assertEquals('Required', $item->ModerationRequired);
$this->assertDOSEquals(array( $this->assertDOSEquals(array(
@ -77,14 +101,14 @@ class CommentsTest extends FunctionalTest
$this->assertEquals(1, $item->Comments()->Count()); $this->assertEquals(1, $item->Comments()->Count());
// require_moderation_nonmembers still filters out unmoderated comments // 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()); $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()); $this->assertEquals(2, $item->Comments()->Count());
// With unmoderated comments set to display in frontend // With unmoderated comments set to display in frontend
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'require_moderation' => true, 'require_moderation' => true,
'frontend_moderation' => true 'frontend_moderation' => true
)); ));
@ -94,7 +118,7 @@ class CommentsTest extends FunctionalTest
$this->assertEquals(2, $item->Comments()->Count()); $this->assertEquals(2, $item->Comments()->Count());
// With spam comments set to display in frontend // With spam comments set to display in frontend
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'require_moderation' => true, 'require_moderation' => true,
'frontend_moderation' => false, 'frontend_moderation' => false,
'frontend_spam' => true, 'frontend_spam' => true,
@ -109,7 +133,7 @@ class CommentsTest extends FunctionalTest
// With spam and unmoderated comments set to display in frontend // 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, 'require_moderation' => true,
'frontend_moderation' => true, 'frontend_moderation' => true,
'frontend_spam' => true, 'frontend_spam' => true,
@ -130,12 +154,12 @@ class CommentsTest extends FunctionalTest
{ {
// comments don't require moderation so unmoderated comments can be // comments don't require moderation so unmoderated comments can be
// shown but not spam posts // shown but not spam posts
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'require_moderation' => true, 'require_moderation' => true,
'require_moderation_cms' => true, 'require_moderation_cms' => true,
)); ));
$item = $this->objFromFixture('CommentableItem', 'spammed'); $item = $this->objFromFixture(CommentableItem::class, 'spammed');
$this->assertEquals('None', $item->ModerationRequired); $this->assertEquals('None', $item->ModerationRequired);
$this->assertDOSEquals(array( $this->assertDOSEquals(array(
@ -170,13 +194,13 @@ class CommentsTest extends FunctionalTest
public function testCanPostComment() public function testCanPostComment()
{ {
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'require_login' => false, 'require_login' => false,
'require_login_cms' => false, 'require_login_cms' => false,
'required_permission' => false, 'required_permission' => false,
)); ));
$item = $this->objFromFixture('CommentableItem', 'first'); $item = $this->objFromFixture(CommentableItem::class, 'first');
$item2 = $this->objFromFixture('CommentableItem', 'second'); $item2 = $this->objFromFixture(CommentableItem::class, 'second');
// Test restriction free commenting // Test restriction free commenting
if ($member = Member::currentUser()) { if ($member = Member::currentUser()) {
@ -186,7 +210,7 @@ class CommentsTest extends FunctionalTest
$this->assertTrue($item->canPostComment()); $this->assertTrue($item->canPostComment());
// Test permission required to post // Test permission required to post
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'require_login' => true, 'require_login' => true,
'required_permission' => 'POSTING_PERMISSION', 'required_permission' => 'POSTING_PERMISSION',
)); ));
@ -200,7 +224,7 @@ class CommentsTest extends FunctionalTest
$this->assertTrue($item->canPostComment()); $this->assertTrue($item->canPostComment());
// Test require login to post, but not any permissions // 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, 'required_permission' => false,
)); ));
$this->assertTrue($item->CommentsRequireLogin); $this->assertTrue($item->CommentsRequireLogin);
@ -212,7 +236,7 @@ class CommentsTest extends FunctionalTest
$this->assertTrue($item->canPostComment()); $this->assertTrue($item->canPostComment());
// Test options set via CMS // Test options set via CMS
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'require_login' => true, 'require_login' => true,
'require_login_cms' => true, 'require_login_cms' => true,
)); ));
@ -235,12 +259,12 @@ class CommentsTest extends FunctionalTest
if ($member = Member::currentUser()) { if ($member = Member::currentUser()) {
$member->logOut(); $member->logOut();
} }
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$commentID = $comment->ID; $commentID = $comment->ID;
$this->assertNull($comment->DeleteLink(), 'No permission to see delete link'); $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()); $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()); $this->assertTrue($check && $check->exists());
// Test non-authenticated user // Test non-authenticated user
@ -249,16 +273,16 @@ class CommentsTest extends FunctionalTest
// Test authenticated user // Test authenticated user
$this->logInAs('commentadmin'); $this->logInAs('commentadmin');
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$commentID = $comment->ID; $commentID = $comment->ID;
$adminComment1Link = $comment->DeleteLink(); $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 // Test that this link can't be shared / XSS exploited
$this->logInAs('commentadmin2'); $this->logInAs('commentadmin2');
$delete = $this->get($adminComment1Link); $delete = $this->get($adminComment1Link);
$this->assertEquals(400, $delete->getStatusCode()); $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()); $this->assertTrue($check && $check->exists());
// Test that this other admin can delete the comment with their own link // Test that this other admin can delete the comment with their own link
@ -267,7 +291,7 @@ class CommentsTest extends FunctionalTest
$this->autoFollowRedirection = false; $this->autoFollowRedirection = false;
$delete = $this->get($adminComment2Link); $delete = $this->get($adminComment2Link);
$this->assertEquals(302, $delete->getStatusCode()); $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()); $this->assertFalse($check && $check->exists());
} }
@ -277,12 +301,12 @@ class CommentsTest extends FunctionalTest
if ($member = Member::currentUser()) { if ($member = Member::currentUser()) {
$member->logOut(); $member->logOut();
} }
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$commentID = $comment->ID; $commentID = $comment->ID;
$this->assertNull($comment->SpamLink(), 'No permission to see mark as spam link'); $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()); $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'); $this->assertEquals(0, $check->IsSpam, 'No permission to mark as spam');
// Test non-authenticated user // Test non-authenticated user
@ -291,16 +315,16 @@ class CommentsTest extends FunctionalTest
// Test authenticated user // Test authenticated user
$this->logInAs('commentadmin'); $this->logInAs('commentadmin');
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$commentID = $comment->ID; $commentID = $comment->ID;
$adminComment1Link = $comment->SpamLink(); $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 // Test that this link can't be shared / XSS exploited
$this->logInAs('commentadmin2'); $this->logInAs('commentadmin2');
$spam = $this->get($adminComment1Link); $spam = $this->get($adminComment1Link);
$this->assertEquals(400, $spam->getStatusCode()); $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'); $this->assertEquals(0, $check->IsSpam, 'No permission to mark as spam');
// Test that this other admin can spam the comment with their own link // Test that this other admin can spam the comment with their own link
@ -309,7 +333,7 @@ class CommentsTest extends FunctionalTest
$this->autoFollowRedirection = false; $this->autoFollowRedirection = false;
$spam = $this->get($adminComment2Link); $spam = $this->get($adminComment2Link);
$this->assertEquals(302, $spam->getStatusCode()); $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); $this->assertEquals(1, $check->IsSpam);
// Cannot re-spam spammed comment // Cannot re-spam spammed comment
@ -322,12 +346,12 @@ class CommentsTest extends FunctionalTest
if ($member = Member::currentUser()) { if ($member = Member::currentUser()) {
$member->logOut(); $member->logOut();
} }
$comment = $this->objFromFixture('Comment', 'secondComC'); $comment = $this->objFromFixture(Comment::class, 'secondComC');
$commentID = $comment->ID; $commentID = $comment->ID;
$this->assertNull($comment->HamLink(), 'No permission to see mark as ham link'); $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()); $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'); $this->assertEquals(1, $check->IsSpam, 'No permission to mark as ham');
// Test non-authenticated user // Test non-authenticated user
@ -336,16 +360,16 @@ class CommentsTest extends FunctionalTest
// Test authenticated user // Test authenticated user
$this->logInAs('commentadmin'); $this->logInAs('commentadmin');
$comment = $this->objFromFixture('Comment', 'secondComC'); $comment = $this->objFromFixture(Comment::class, 'secondComC');
$commentID = $comment->ID; $commentID = $comment->ID;
$adminComment1Link = $comment->HamLink(); $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 // Test that this link can't be shared / XSS exploited
$this->logInAs('commentadmin2'); $this->logInAs('commentadmin2');
$ham = $this->get($adminComment1Link); $ham = $this->get($adminComment1Link);
$this->assertEquals(400, $ham->getStatusCode()); $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'); $this->assertEquals(1, $check->IsSpam, 'No permission to mark as ham');
// Test that this other admin can ham the comment with their own link // Test that this other admin can ham the comment with their own link
@ -354,7 +378,7 @@ class CommentsTest extends FunctionalTest
$this->autoFollowRedirection = false; $this->autoFollowRedirection = false;
$ham = $this->get($adminComment2Link); $ham = $this->get($adminComment2Link);
$this->assertEquals(302, $ham->getStatusCode()); $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); $this->assertEquals(0, $check->IsSpam);
// Cannot re-ham hammed comment // Cannot re-ham hammed comment
@ -367,12 +391,12 @@ class CommentsTest extends FunctionalTest
if ($member = Member::currentUser()) { if ($member = Member::currentUser()) {
$member->logOut(); $member->logOut();
} }
$comment = $this->objFromFixture('Comment', 'secondComB'); $comment = $this->objFromFixture(Comment::class, 'secondComB');
$commentID = $comment->ID; $commentID = $comment->ID;
$this->assertNull($comment->ApproveLink(), 'No permission to see approve link'); $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()); $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'); $this->assertEquals(0, $check->Moderated, 'No permission to approve');
// Test non-authenticated user // Test non-authenticated user
@ -381,16 +405,16 @@ class CommentsTest extends FunctionalTest
// Test authenticated user // Test authenticated user
$this->logInAs('commentadmin'); $this->logInAs('commentadmin');
$comment = $this->objFromFixture('Comment', 'secondComB'); $comment = $this->objFromFixture(Comment::class, 'secondComB');
$commentID = $comment->ID; $commentID = $comment->ID;
$adminComment1Link = $comment->ApproveLink(); $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 // Test that this link can't be shared / XSS exploited
$this->logInAs('commentadmin2'); $this->logInAs('commentadmin2');
$approve = $this->get($adminComment1Link); $approve = $this->get($adminComment1Link);
$this->assertEquals(400, $approve->getStatusCode()); $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'); $this->assertEquals(0, $check->Moderated, 'No permission to approve');
// Test that this other admin can approve the comment with their own link // Test that this other admin can approve the comment with their own link
@ -399,7 +423,7 @@ class CommentsTest extends FunctionalTest
$this->autoFollowRedirection = false; $this->autoFollowRedirection = false;
$approve = $this->get($adminComment2Link); $approve = $this->get($adminComment2Link);
$this->assertEquals(302, $approve->getStatusCode()); $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); $this->assertEquals(1, $check->Moderated);
// Cannot re-approve approved comment // Cannot re-approve approved comment
@ -427,21 +451,21 @@ class CommentsTest extends FunctionalTest
public function testSanitizesWithAllowHtml() public function testSanitizesWithAllowHtml()
{ {
if (!class_exists('HTMLPurifier')) { if (!class_exists('\\HTMLPurifier')) {
$this->markTestSkipped('HTMLPurifier class not found'); $this->markTestSkipped('HTMLPurifier class not found');
return; return;
} }
// Add p for paragraph // Add p for paragraph
// NOTE: The config method appears to append to the existing array // 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'), 'html_allowed_elements' => array('p'),
)); ));
// Without HTML allowed // Without HTML allowed
$comment1 = new Comment(); $comment1 = new Comment();
$comment1->AllowHtml = false; $comment1->AllowHtml = false;
$comment1->BaseClass = 'CommentableItem'; $comment1->BaseClass = CommentableItem::class;
$comment1->Comment = '<p><script>alert("w00t")</script>my comment</p>'; $comment1->Comment = '<p><script>alert("w00t")</script>my comment</p>';
$comment1->write(); $comment1->write();
$this->assertEquals( $this->assertEquals(
@ -454,7 +478,7 @@ class CommentsTest extends FunctionalTest
// With HTML allowed // With HTML allowed
$comment2 = new Comment(); $comment2 = new Comment();
$comment2->AllowHtml = true; $comment2->AllowHtml = true;
$comment2->BaseClass = 'CommentableItem'; $comment2->ParentClass = CommentableItem::class;
$comment2->Comment = '<p><script>alert("w00t")</script>my comment</p>'; $comment2->Comment = '<p><script>alert("w00t")</script>my comment</p>';
$comment2->write(); $comment2->write();
$this->assertEquals( $this->assertEquals(
@ -466,11 +490,11 @@ class CommentsTest extends FunctionalTest
public function testDefaultTemplateRendersHtmlWithAllowHtml() public function testDefaultTemplateRendersHtmlWithAllowHtml()
{ {
if (!class_exists('HTMLPurifier')) { if (!class_exists('\\HTMLPurifier')) {
$this->markTestSkipped('HTMLPurifier class not found'); $this->markTestSkipped('HTMLPurifier class not found');
} }
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'html_allowed_elements' => array('p'), 'html_allowed_elements' => array('p'),
)); ));
@ -482,7 +506,7 @@ class CommentsTest extends FunctionalTest
$comment->Comment = '<p>my comment</p>'; $comment->Comment = '<p>my comment</p>';
$comment->AllowHtml = false; $comment->AllowHtml = false;
$comment->ParentID = $item->ID; $comment->ParentID = $item->ID;
$comment->BaseClass = 'CommentableItem'; $comment->BaseClass = CommentableItem::class;
$comment->write(); $comment->write();
$html = $item->customise(array('CommentsEnabled' => true))->renderWith('CommentsInterface'); $html = $item->customise(array('CommentsEnabled' => true))->renderWith('CommentsInterface');
@ -507,7 +531,7 @@ class CommentsTest extends FunctionalTest
public function testDefaultEnabled() public function testDefaultEnabled()
{ {
// Ensure values are set via cms (not via config) // 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, 'enabled_cms' => true,
'require_moderation_cms' => true, 'require_moderation_cms' => true,
'require_login_cms' => true 'require_login_cms' => true
@ -532,13 +556,13 @@ class CommentsTest extends FunctionalTest
// With default = false // With default = false
// Because of config rules about falsey values, apply config to object directly // 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, 'enabled' => false,
'require_login' => true, 'require_login' => true,
'require_moderation' => true 'require_moderation' => true
)); ));
$obj = new CommentableItem(); $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->assertFalse((bool)$obj->ProvideComments);
$this->assertEquals('Required', $obj->ModerationRequired); $this->assertEquals('Required', $obj->ModerationRequired);
$this->assertTrue((bool)$obj->CommentsRequireLogin); $this->assertTrue((bool)$obj->CommentsRequireLogin);
@ -559,7 +583,7 @@ class CommentsTest extends FunctionalTest
*/ */
public function testOnBeforeDelete() public function testOnBeforeDelete()
{ {
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$child = new Comment(); $child = new Comment();
$child->Name = 'Fred Bloggs'; $child->Name = 'Fred Bloggs';
@ -574,8 +598,8 @@ class CommentsTest extends FunctionalTest
$comment->delete(); $comment->delete();
// assert that the new child been deleted // assert that the new child been deleted
$this->assertFalse(DataObject::get_by_id('Comment', $commentID)); $this->assertFalse(DataObject::get_by_id(Comment::class, $commentID));
$this->assertFalse(DataObject::get_by_id('Comment', $childCommentID)); $this->assertFalse(DataObject::get_by_id(Comment::class, $childCommentID));
} }
public function testRequireDefaultRecords() public function testRequireDefaultRecords()
@ -585,41 +609,42 @@ class CommentsTest extends FunctionalTest
public function testLink() public function testLink()
{ {
$comment = $this->objFromFixture('Comment', 'thirdComD'); $comment = $this->objFromFixture(Comment::class, 'thirdComD');
$this->assertEquals('CommentableItem_Controller#comment-'.$comment->ID, $this->assertEquals(
$comment->Link()); 'CommentableItemController#comment-' . $comment->ID,
$comment->Link()
);
$this->assertEquals($comment->ID, $comment->ID); $this->assertEquals($comment->ID, $comment->ID);
// An orphan comment has no link // An orphan comment has no link
$comment->ParentID = 0; $comment->ParentID = 0;
$comment->ParentClass = null;
$comment->write(); $comment->write();
$this->assertEquals('', $comment->Link()); $this->assertEquals('', $comment->Link());
} }
public function testPermalink() public function testPermalink()
{ {
$comment = $this->objFromFixture('Comment', 'thirdComD'); $comment = $this->objFromFixture(Comment::class, 'thirdComD');
$this->assertEquals('comment-' . $comment->ID, $comment->Permalink()); $this->assertEquals('comment-' . $comment->ID, $comment->Permalink());
} }
/* /**
Test field labels in 2 languages * Test field labels in 2 languages
*/ */
public function testFieldLabels() public function testFieldLabels()
{ {
$locale = i18n::get_locale(); $locale = i18n::get_locale();
i18n::set_locale('fr'); i18n::set_locale('fr');
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$labels = $comment->FieldLabels(); $labels = $comment->FieldLabels();
$expected = array( $expected = array(
'Name' => 'Nom de l\'Auteur', 'Name' => 'Nom de l\'Auteur',
'Comment' => 'Commentaire', 'Comment' => 'Commentaire',
'Email' => 'Email', 'Email' => 'Email',
'URL' => 'URL', 'URL' => 'URL',
'BaseClass' => 'Base Class',
'Moderated' => 'Modéré?', 'Moderated' => 'Modéré?',
'IsSpam' => 'Spam?', 'IsSpam' => 'Spam?',
'ParentID' => 'Parent ID',
'AllowHtml' => 'Allow Html', 'AllowHtml' => 'Allow Html',
'SecretToken' => 'Secret Token', 'SecretToken' => 'Secret Token',
'Depth' => 'Depth', 'Depth' => 'Depth',
@ -627,7 +652,8 @@ class CommentsTest extends FunctionalTest
'ParentComment' => 'Parent Comment', 'ParentComment' => 'Parent Comment',
'ChildComments' => 'Child Comments', 'ChildComments' => 'Child Comments',
'ParentTitle' => 'Parent', 'ParentTitle' => 'Parent',
'Created' => 'Date de publication' 'Created' => 'Date de publication',
'Parent' => 'Parent'
); );
i18n::set_locale($locale); i18n::set_locale($locale);
$this->assertEquals($expected, $labels); $this->assertEquals($expected, $labels);
@ -637,10 +663,8 @@ class CommentsTest extends FunctionalTest
'Comment' => 'Comment', 'Comment' => 'Comment',
'Email' => 'Email', 'Email' => 'Email',
'URL' => 'URL', 'URL' => 'URL',
'BaseClass' => 'Base Class',
'Moderated' => 'Moderated?', 'Moderated' => 'Moderated?',
'IsSpam' => 'Spam?', 'IsSpam' => 'Spam?',
'ParentID' => 'Parent ID',
'AllowHtml' => 'Allow Html', 'AllowHtml' => 'Allow Html',
'SecretToken' => 'Secret Token', 'SecretToken' => 'Secret Token',
'Depth' => 'Depth', 'Depth' => 'Depth',
@ -648,8 +672,8 @@ class CommentsTest extends FunctionalTest
'ParentComment' => 'Parent Comment', 'ParentComment' => 'Parent Comment',
'ChildComments' => 'Child Comments', 'ChildComments' => 'Child Comments',
'ParentTitle' => 'Parent', 'ParentTitle' => 'Parent',
'Created' => 'Date posted' 'Created' => 'Date posted',
'Parent' => 'Parent'
); );
$this->assertEquals($expected, $labels); $this->assertEquals($expected, $labels);
} }
@ -661,29 +685,31 @@ class CommentsTest extends FunctionalTest
public function testGetParent() public function testGetParent()
{ {
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$item = $this->objFromFixture('CommentableItem', 'first'); $item = $this->objFromFixture(CommentableItem::class, 'first');
$parent = $comment->getParent(); $parent = $comment->Parent();
$this->assertEquals($item, $parent); $this->assertSame($item->getClassName(), $parent->getClassName());
$this->assertSame($item->ID, $parent->ID);
} }
public function testGetParentTitle() public function testGetParentTitle()
{ {
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$title = $comment->getParentTitle(); $title = $comment->getParentTitle();
$this->assertEquals('First', $title); $this->assertEquals('First', $title);
// Title from a comment with no parent is blank // Title from a comment with no parent is blank
$comment->ParentID = 0; $comment->ParentID = 0;
$comment->ParentClass = null;
$comment->write(); $comment->write();
$this->assertEquals('', $comment->getParentTitle()); $this->assertEquals('', $comment->getParentTitle());
} }
public function testGetParentClassName() public function testGetParentClassName()
{ {
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$className = $comment->getParentClassName(); $className = $comment->getParentClassName();
$this->assertEquals('CommentableItem', $className); $this->assertEquals(CommentableItem::class, $className);
} }
public function testCastingHelper() public function testCastingHelper()
@ -708,7 +734,7 @@ class CommentsTest extends FunctionalTest
public function testCanCreate() public function testCanCreate()
{ {
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
// admin can create - this is always false // admin can create - this is always false
$this->logInAs('commentadmin'); $this->logInAs('commentadmin');
@ -721,7 +747,7 @@ class CommentsTest extends FunctionalTest
public function testCanView() public function testCanView()
{ {
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
// admin can view // admin can view
$this->logInAs('commentadmin'); $this->logInAs('commentadmin');
@ -738,7 +764,7 @@ class CommentsTest extends FunctionalTest
public function testCanEdit() public function testCanEdit()
{ {
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
// admin can edit // admin can edit
$this->logInAs('commentadmin'); $this->logInAs('commentadmin');
@ -755,7 +781,7 @@ class CommentsTest extends FunctionalTest
public function testCanDelete() public function testCanDelete()
{ {
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
// admin can delete // admin can delete
$this->logInAs('commentadmin'); $this->logInAs('commentadmin');
@ -774,7 +800,7 @@ class CommentsTest extends FunctionalTest
{ {
$this->logInAs('visitor'); $this->logInAs('visitor');
$current = Member::currentUser(); $current = Member::currentUser();
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$method = $this->getMethod('getMember'); $method = $this->getMethod('getMember');
// null case // null case
@ -792,7 +818,7 @@ class CommentsTest extends FunctionalTest
public function testGetAuthorName() public function testGetAuthorName()
{ {
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$this->assertEquals( $this->assertEquals(
'FA', 'FA',
$comment->getAuthorName() $comment->getAuthorName()
@ -804,7 +830,7 @@ class CommentsTest extends FunctionalTest
$comment->getAuthorName() $comment->getAuthorName()
); );
$author = $this->objFromFixture('Member', 'visitor'); $author = $this->objFromFixture(Member::class, 'visitor');
$comment->AuthorID = $author->ID; $comment->AuthorID = $author->ID;
$comment->write(); $comment->write();
$this->assertEquals( $this->assertEquals(
@ -821,44 +847,44 @@ class CommentsTest extends FunctionalTest
public function testLinks() public function testLinks()
{ {
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$this->logInAs('commentadmin'); $this->logInAs('commentadmin');
$method = $this->getMethod('ActionLink'); $method = $this->getMethod('ActionLink');
// test with starts of strings and tokens and salts change each time // test with starts of strings and tokens and salts change each time
$this->assertStringStartsWith( $this->assertStringStartsWith(
'/CommentingController/theaction/'.$comment->ID, '/comments/theaction/' . $comment->ID,
$method->invokeArgs($comment, array('theaction')) $method->invokeArgs($comment, array('theaction'))
); );
$this->assertStringStartsWith( $this->assertStringStartsWith(
'/CommentingController/delete/'.$comment->ID, '/comments/delete/' . $comment->ID,
$comment->DeleteLink() $comment->DeleteLink()
); );
$this->assertStringStartsWith( $this->assertStringStartsWith(
'/CommentingController/spam/'.$comment->ID, '/comments/spam/' . $comment->ID,
$comment->SpamLink() $comment->SpamLink()
); );
$comment->markSpam(); $comment->markSpam();
$this->assertStringStartsWith( $this->assertStringStartsWith(
'/CommentingController/ham/'.$comment->ID, '/comments/ham/' . $comment->ID,
$comment->HamLink() $comment->HamLink()
); );
//markApproved //markApproved
$comment->markUnapproved(); $comment->markUnapproved();
$this->assertStringStartsWith( $this->assertStringStartsWith(
'/CommentingController/approve/'.$comment->ID, '/comments/approve/' . $comment->ID,
$comment->ApproveLink() $comment->ApproveLink()
); );
} }
public function testMarkSpam() public function testMarkSpam()
{ {
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$comment->markSpam(); $comment->markSpam();
$this->assertTrue($comment->Moderated); $this->assertTrue($comment->Moderated);
$this->assertTrue($comment->IsSpam); $this->assertTrue($comment->IsSpam);
@ -866,7 +892,7 @@ class CommentsTest extends FunctionalTest
public function testMarkApproved() public function testMarkApproved()
{ {
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$comment->markApproved(); $comment->markApproved();
$this->assertTrue($comment->Moderated); $this->assertTrue($comment->Moderated);
$this->assertFalse($comment->IsSpam); $this->assertFalse($comment->IsSpam);
@ -874,14 +900,14 @@ class CommentsTest extends FunctionalTest
public function testMarkUnapproved() public function testMarkUnapproved()
{ {
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$comment->markApproved(); $comment->markApproved();
$this->assertTrue($comment->Moderated); $this->assertTrue($comment->Moderated);
} }
public function testSpamClass() public function testSpamClass()
{ {
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$this->assertEquals('notspam', $comment->spamClass()); $this->assertEquals('notspam', $comment->spamClass());
$comment->Moderated = false; $comment->Moderated = false;
$this->assertEquals('unmoderated', $comment->spamClass()); $this->assertEquals('unmoderated', $comment->spamClass());
@ -891,7 +917,7 @@ class CommentsTest extends FunctionalTest
public function testGetTitle() public function testGetTitle()
{ {
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$this->assertEquals( $this->assertEquals(
'Comment by FA on First', 'Comment by FA on First',
$comment->getTitle() $comment->getTitle()
@ -900,7 +926,7 @@ class CommentsTest extends FunctionalTest
public function testGetCMSFields() public function testGetCMSFields()
{ {
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$fields = $comment->getCMSFields(); $fields = $comment->getCMSFields();
$names = array(); $names = array();
foreach ($fields as $field) { foreach ($fields as $field) {
@ -912,7 +938,7 @@ class CommentsTest extends FunctionalTest
'Comment', 'Comment',
'Email', 'Email',
'URL', 'URL',
null #FIXME this is suspicious 'Options'
); );
$this->assertEquals($expected, $names); $this->assertEquals($expected, $names);
} }
@ -920,7 +946,7 @@ class CommentsTest extends FunctionalTest
public function testGetCMSFieldsCommentHasAuthor() public function testGetCMSFieldsCommentHasAuthor()
{ {
$member = Member::get()->filter('FirstName', 'visitor')->first(); $member = Member::get()->filter('FirstName', 'visitor')->first();
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$comment->AuthorID = $member->ID; $comment->AuthorID = $member->ID;
$comment->write(); $comment->write();
@ -936,14 +962,14 @@ class CommentsTest extends FunctionalTest
'Comment', 'Comment',
'Email', 'Email',
'URL', 'URL',
null #FIXME this is suspicious 'Options'
); );
$this->assertEquals($expected, $names); $this->assertEquals($expected, $names);
} }
public function testGetCMSFieldsWithParentComment() public function testGetCMSFieldsWithParentComment()
{ {
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$child = new Comment(); $child = new Comment();
$child->Name = 'John Smith'; $child->Name = 'John Smith';
@ -962,7 +988,7 @@ class CommentsTest extends FunctionalTest
'Comment', 'Comment',
'Email', 'Email',
'URL', 'URL',
null, #FIXME this is suspicious 'Options',
'ParentComment_Title', 'ParentComment_Title',
'ParentComment_Created', 'ParentComment_Created',
'ParentComment_AuthorName', 'ParentComment_AuthorName',
@ -971,10 +997,9 @@ class CommentsTest extends FunctionalTest
$this->assertEquals($expected, $names); $this->assertEquals($expected, $names);
} }
public function testPurifyHtml() public function testPurifyHtml()
{ {
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$dirtyHTML = '<p><script>alert("w00t")</script>my comment</p>'; $dirtyHTML = '<p><script>alert("w00t")</script>my comment</p>';
$this->assertEquals( $this->assertEquals(
@ -986,22 +1011,22 @@ class CommentsTest extends FunctionalTest
public function testGravatar() public function testGravatar()
{ {
// Turn gravatars on // Turn gravatars on
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'use_gravatar' => true 'use_gravatar' => true
)); ));
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$this->assertEquals( $this->assertEquals(
'http://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e?s'. 'http://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e?s'
'=80&d=identicon&r=g', . '=80&d=identicon&r=g',
$comment->gravatar() $comment->gravatar()
); );
// Turn gravatars off // Turn gravatars off
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'use_gravatar' => false 'use_gravatar' => false
)); ));
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$this->assertEquals( $this->assertEquals(
'', '',
@ -1011,13 +1036,13 @@ class CommentsTest extends FunctionalTest
public function testGetRepliesEnabled() public function testGetRepliesEnabled()
{ {
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => false 'nested_comments' => false
)); ));
$this->assertFalse($comment->getRepliesEnabled()); $this->assertFalse($comment->getRepliesEnabled());
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => true, 'nested_comments' => true,
'nested_depth' => 4 'nested_depth' => 4
)); ));
@ -1028,7 +1053,7 @@ class CommentsTest extends FunctionalTest
// 0 indicates no limit for nested_depth // 0 indicates no limit for nested_depth
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => true, 'nested_comments' => true,
'nested_depth' => 0 'nested_depth' => 0
)); ));
@ -1046,11 +1071,11 @@ class CommentsTest extends FunctionalTest
public function testAllReplies() public function testAllReplies()
{ {
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => true, 'nested_comments' => true,
'nested_depth' => 4 'nested_depth' => 4
)); ));
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$this->assertEquals( $this->assertEquals(
3, 3,
$comment->allReplies()->count() $comment->allReplies()->count()
@ -1069,7 +1094,7 @@ class CommentsTest extends FunctionalTest
$comment->allReplies()->count() $comment->allReplies()->count()
); );
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => false 'nested_comments' => false
)); ));
@ -1078,13 +1103,13 @@ class CommentsTest extends FunctionalTest
public function testReplies() public function testReplies()
{ {
CommentableItem::add_extension('CommentsExtension'); CommentableItem::add_extension(CommentsExtension::class);
$this->logInWithPermission('ADMIN'); $this->logInWithPermission('ADMIN');
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => true, 'nested_comments' => true,
'nested_depth' => 4 'nested_depth' => 4
)); ));
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$this->assertEquals( $this->assertEquals(
3, 3,
$comment->Replies()->count() $comment->Replies()->count()
@ -1114,17 +1139,17 @@ class CommentsTest extends FunctionalTest
// Test moderation required on the front end // Test moderation required on the front end
$item = $this->objFromFixture('CommentableItem', 'first'); $item = $this->objFromFixture(CommentableItem::class, 'first');
$item->ModerationRequired = 'Required'; $item->ModerationRequired = 'Required';
$item->write(); $item->write();
Config::inst()->update('CommentableItemDisabled', 'comments', array( Config::inst()->update(CommentableItemDisabled::class, 'comments', array(
'nested_comments' => true, 'nested_comments' => true,
'nested_depth' => 4, 'nested_depth' => 4,
'frontend_moderation' => true 'frontend_moderation' => true
)); ));
$comment = DataObject::get_by_id('Comment', $comment->ID); $comment = DataObject::get_by_id(Comment::class, $comment->ID);
$this->assertEquals( $this->assertEquals(
2, 2,
@ -1132,7 +1157,7 @@ class CommentsTest extends FunctionalTest
); );
// Turn off nesting, empty array should be returned // Turn off nesting, empty array should be returned
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => false 'nested_comments' => false
)); ));
@ -1141,18 +1166,18 @@ class CommentsTest extends FunctionalTest
$comment->Replies()->count() $comment->Replies()->count()
); );
CommentableItem::remove_extension('CommentsExtension'); CommentableItem::remove_extension(CommentsExtension::class);
} }
public function testPagedReplies() public function testPagedReplies()
{ {
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => true, 'nested_comments' => true,
'nested_depth' => 4, 'nested_depth' => 4,
'comments_per_page' => 2 #Force 2nd page for 3 items 'comments_per_page' => 2 #Force 2nd page for 3 items
)); ));
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$pagedList = $comment->pagedReplies(); $pagedList = $comment->pagedReplies();
$this->assertEquals( $this->assertEquals(
2, 2,
@ -1164,7 +1189,7 @@ class CommentsTest extends FunctionalTest
); );
//TODO - 2nd page requires controller //TODO - 2nd page requires controller
// //
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => false 'nested_comments' => false
)); ));
@ -1173,19 +1198,19 @@ class CommentsTest extends FunctionalTest
public function testReplyForm() public function testReplyForm()
{ {
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => false, 'nested_comments' => false,
'nested_depth' => 4 'nested_depth' => 4
)); ));
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
// No nesting, no reply form // No nesting, no reply form
$form = $comment->replyForm(); $form = $comment->replyForm();
$this->assertNull($form); $this->assertNull($form);
// parent item so show form // parent item so show form
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => true, 'nested_comments' => true,
'nested_depth' => 4 'nested_depth' => 4
)); ));
@ -1198,11 +1223,11 @@ class CommentsTest extends FunctionalTest
$this->assertEquals( $this->assertEquals(
array( array(
null, #FIXME suspicious 'NameEmailURLComment', // The CompositeField name?
'ParentID', 'ParentID',
'ParentClassName',
'ReturnURL', 'ReturnURL',
'ParentCommentID', 'ParentCommentID'
'BaseClass'
), ),
$names $names
); );
@ -1210,6 +1235,7 @@ class CommentsTest extends FunctionalTest
// no parent, no reply form // no parent, no reply form
$comment->ParentID = 0; $comment->ParentID = 0;
$comment->ParentClass = null;
$comment->write(); $comment->write();
$form = $comment->replyForm(); $form = $comment->replyForm();
$this->assertNull($form); $this->assertNull($form);
@ -1217,12 +1243,12 @@ class CommentsTest extends FunctionalTest
public function testUpdateDepth() public function testUpdateDepth()
{ {
Config::inst()->update('CommentableItem', 'comments', array( Config::inst()->update(CommentableItem::class, 'comments', array(
'nested_comments' => true, 'nested_comments' => true,
'nested_depth' => 4 'nested_depth' => 4
)); ));
$comment = $this->objFromFixture('Comment', 'firstComA'); $comment = $this->objFromFixture(Comment::class, 'firstComA');
$children = $comment->allReplies()->toArray(); $children = $comment->allReplies()->toArray();
// Make the second child a child of the first // Make the second child a child of the first
// Make the third child a child of the second // Make the third child a child of the second
@ -1262,98 +1288,11 @@ class CommentsTest extends FunctionalTest
$this->markTestSkipped('TODO'); $this->markTestSkipped('TODO');
} }
protected static function getMethod($name) protected static function getMethod($name)
{ {
$class = new ReflectionClass('Comment'); $class = new ReflectionClass(Comment::class);
$method = $class->getMethod($name); $method = $class->getMethod($name);
$method->setAccessible(true); $method->setAccessible(true);
return $method; 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: commentadmin:
FirstName: admin FirstName: admin
commentadmin2: commentadmin2:
@ -6,17 +6,17 @@ Member:
visitor: visitor:
FirstName: visitor FirstName: visitor
Group: SilverStripe\Security\Group:
commentadmins: commentadmins:
Title: Admin Title: Admin
Members: =>Member.commentadmin, =>Member.commentadmin2 Members: =>SilverStripe\Security\Member.commentadmin, =>SilverStripe\Security\Member.commentadmin2
Permission: SilverStripe\Security\Permission:
admin: admin:
Code: CMS_ACCESS_CommentAdmin Code: CMS_ACCESS_CommentAdmin
Group: =>Group.commentadmins Group: =>SilverStripe\Security\Group.commentadmins
CommentableItem: SilverStripe\Comments\Tests\Stubs\CommentableItem:
first: first:
Title: First Title: First
ProvideComments: 1 ProvideComments: 1
@ -35,166 +35,158 @@ CommentableItem:
ProvideComments: 1 ProvideComments: 1
Title: spammed Title: spammed
ModerationRequired: 'None' ModerationRequired: 'None'
moderated:
ProvideComments: 1
Title: Moderate everything
ModerationRequired: Required
CommentsRequireLogin: 0
Comment: SilverStripe\Comments\Model\Comment:
firstComA: firstComA:
ParentID: =>CommentableItem.first Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.first
Name: FA Name: FA
Comment: textFA Comment: textFA
BaseClass: CommentableItem
Moderated: 1 Moderated: 1
IsSpam: IsSpam:
Depth: 1 Depth: 1
firstComAChild1: firstComAChild1:
ParentID: =>CommentableItem.first Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.first
ParentCommentID: =>Comment.firstComA ParentComment: =>SilverStripe\Comments\Model\Comment.firstComA
Name: John Smith Name: John Smith
Comment: Reply to firstComA 1 Comment: Reply to firstComA 1
BaseClass: CommentableItem
Moderated: 1 Moderated: 1
IsSpam: 0 IsSpam: 0
Depth: 2 Depth: 2
firstComAChild2: firstComAChild2:
ParentID: =>CommentableItem.first Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.first
ParentCommentID: =>Comment.firstComA ParentComment: =>SilverStripe\Comments\Model\Comment.firstComA
Name: John Smith Name: John Smith
Comment: Reply to firstComA 2 Comment: Reply to firstComA 2
BaseClass: CommentableItem
Moderated: 1 Moderated: 1
IsSpam: 0 IsSpam: 0
Depth: 2 Depth: 2
firstComAChild3: firstComAChild3:
ParentID: =>CommentableItem.first Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.first
ParentCommentID: =>Comment.firstComA ParentComment: =>SilverStripe\Comments\Model\Comment.firstComA
Name: John Smith Name: John Smith
Comment: Reply to firstComA 3 Comment: Reply to firstComA 3
BaseClass: CommentableItem
Moderated: 1 Moderated: 1
IsSpam: 0 IsSpam: 0
Depth: 2 Depth: 2
secondComA: secondComA:
ParentID: =>CommentableItem.second Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.second
Name: SA Name: SA
Comment: textSA Comment: textSA
Moderated: 1 Moderated: 1
IsSpam: 0 IsSpam: 0
BaseClass: CommentableItem
secondComB: secondComB:
ParentID: =>CommentableItem.second Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.second
Name: SB Name: SB
Comment: textSB Comment: textSB
Moderated: 0 Moderated: 0
IsSpam: 0 IsSpam: 0
BaseClass: CommentableItem
secondComC: secondComC:
ParentID: =>CommentableItem.second Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.second
Name: SB Name: SB
Comment: textSB Comment: textSB
Moderated: 1 Moderated: 1
IsSpam: 1 IsSpam: 1
BaseClass: CommentableItem
thirdComA: thirdComA:
ParentID: =>CommentableItem.third Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TA Name: TA
Comment: textTA Comment: textTA
Moderated: 1 Moderated: 1
IsSpam: 0 IsSpam: 0
BaseClass: CommentableItem
thirdComB: thirdComB:
ParentID: =>CommentableItem.third Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TB Name: TB
Comment: textTB Comment: textTB
Moderated: 1 Moderated: 1
IsSpam: 0 IsSpam: 0
BaseClass: CommentableItem
thirdComC: thirdComC:
ParentID: =>CommentableItem.third Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TC Name: TC
Comment: textTC Comment: textTC
Moderated: 1 Moderated: 1
IsSpam: 0 IsSpam: 0
BaseClass: CommentableItem
thirdComD: thirdComD:
ParentID: =>CommentableItem.third Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TC Name: TC
Comment: textTC Comment: textTC
Moderated: 1 Moderated: 1
BaseClass: CommentableItem
thirdComE: thirdComE:
ParentID: =>CommentableItem.third Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TC Name: TC
Comment: textTC Comment: textTC
Moderated: 1 Moderated: 1
BaseClass: CommentableItem
thirdComF: thirdComF:
ParentID: =>CommentableItem.third Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TC Name: TC
Comment: textTC Comment: textTC
Moderated: 1 Moderated: 1
IsSpam: 0 IsSpam: 0
BaseClass: CommentableItem
thirdComG: thirdComG:
ParentID: =>CommentableItem.third Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TC Name: TC
Comment: textTC Comment: textTC
Moderated: 1 Moderated: 1
IsSpam: 0 IsSpam: 0
BaseClass: CommentableItem
thirdComH: thirdComH:
ParentID: =>CommentableItem.third Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TC Name: TC
Comment: textTC Comment: textTC
Moderated: 1 Moderated: 1
IsSpam: 0 IsSpam: 0
BaseClass: CommentableItem
thirdComI: thirdComI:
ParentID: =>CommentableItem.third Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TC Name: TC
Comment: textTC Comment: textTC
Moderated: 1 Moderated: 1
IsSpam: 0 IsSpam: 0
BaseClass: CommentableItem
thirdComJ: thirdComJ:
ParentID: =>CommentableItem.third Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TC Name: TC
Comment: textTC Comment: textTC
Moderated: 1 Moderated: 1
IsSpam: 0 IsSpam: 0
BaseClass: CommentableItem
thirdComK: thirdComK:
ParentID: =>CommentableItem.third Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.third
Name: TC Name: TC
Comment: textTC Comment: textTC
Moderated: 1 Moderated: 1
IsSpam: 0 IsSpam: 0
BaseClass: CommentableItem
disabledCom: disabledCom:
ParentID: =>CommentableItem.nocomments Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.nocomments
Name: Disabled Name: Disabled
Moderated: 0 Moderated: 0
IsSpam: 1 IsSpam: 1
BaseClass: CommentableItem
testCommentList1: testCommentList1:
ParentID: =>CommentableItem.spammed Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.spammed
Name: Comment 1 Name: Comment 1
Moderated: 0 Moderated: 0
IsSpam: 0 IsSpam: 0
BaseClass: CommentableItem
testCommentList2: testCommentList2:
ParentID: =>CommentableItem.spammed Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.spammed
Name: Comment 2 Name: Comment 2
Moderated: 1 Moderated: 1
IsSpam: 1 IsSpam: 1
BaseClass: CommentableItem
testCommentList3: testCommentList3:
ParentID: =>CommentableItem.spammed Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.spammed
Name: Comment 3 Name: Comment 3
Moderated: 1 Moderated: 1
IsSpam: 0 IsSpam: 0
BaseClass: CommentableItem
testCommentList4: testCommentList4:
ParentID: =>CommentableItem.spammed Parent: =>SilverStripe\Comments\Tests\Stubs\CommentableItem.spammed
Name: Comment 4 Name: Comment 4
Moderated: 0 Moderated: 0
IsSpam: 1 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
);
}