Compare commits
180 Commits
Author | SHA1 | Date |
---|---|---|
github-actions | 26936f33e4 | |
Guy Sartorelli | 5badc345de | |
github-actions | eb858ca76e | |
Guy Sartorelli | 19603c31bc | |
Steve Boyd | 17411fbb95 | |
Guy Sartorelli | 404ae173d0 | |
Steve Boyd | afbcf59ec4 | |
Guy Sartorelli | 5742971245 | |
Guy Sartorelli | 23843cd97f | |
Maxime Rainville | 6ef3acd518 | |
Guy Sartorelli | 3f62dfd4a4 | |
Maxime Rainville | 7c81d075d6 | |
Steve Boyd | 04aefedeef | |
Guy Sartorelli | 754bcee5da | |
Guy Sartorelli | 4971ddf3cb | |
Guy Sartorelli | 9fd768d5ad | |
Guy Sartorelli | 4e3f68cdb1 | |
Steve Boyd | c5d644eb71 | |
Maxime Rainville | 9a7ed5f091 | |
Steve Boyd | ed1d210f0d | |
Maxime Rainville | 1c99bc8b92 | |
Sabina Talipova | 2a55708ae8 | |
Sabina Talipova | 2c8fc03f2f | |
Steve Boyd | 688b438e88 | |
Steve Boyd | fc36247598 | |
Steve Boyd | 0d7a57cedf | |
Guy Sartorelli | 0e5a2dc66d | |
Steve Boyd | 3b0d8d08ed | |
Steve Boyd | e028d76a34 | |
Steve Boyd | 4b7d18fe0e | |
Guy Sartorelli | 8eb3e05f76 | |
Steve Boyd | 63fbae7413 | |
Steve Boyd | 3e9f292082 | |
Steve Boyd | af01b0ad01 | |
Guy Sartorelli | ed7dc6e38e | |
Steve Boyd | d452367262 | |
Maxime Rainville | a2a21988ed | |
Maxime Rainville | 228f2a3058 | |
Maxime Rainville | 68d550b817 | |
Maxime Rainville | 514b6d7a17 | |
Steve Boyd | f7febc1e98 | |
Maxime Rainville | 04eb8df284 | |
Steve Boyd | 46169f71a0 | |
Steve Boyd | 643fedaf21 | |
Steve Boyd | 9c9900f75a | |
Maxime Rainville | ca6f507af8 | |
Maxime Rainville | c2c4342c01 | |
Steve Boyd | 050ef82451 | |
Steve Boyd | 3a8702b1fa | |
3Dgoo | 857389c7ff | |
Steve Boyd | 1459ed89ff | |
Steve Boyd | e717411a9d | |
3Dgoo | d5ae93c88e | |
Steve Boyd | 0db3e7aee0 | |
Serge Latyntsev | 856cc80ffa | |
Steve Boyd | a20b215e5c | |
Steve Boyd | a36bb28b0c | |
Steve Boyd | 6ecccd2625 | |
Garion Herman | 669b189ba7 | |
Robbie Averill | dce36b8fe7 | |
Garion Herman | 5978c62022 | |
Robbie Averill | f3fa9fe9fc | |
Robbie Averill | e024613ede | |
Robbie Averill | b88a706ae7 | |
Will Rossiter | 0c445a1dbf | |
Guy Marriott | 6d39bc23ec | |
Robbie Averill | fc934d93fd | |
Will Rossiter | 506d82fc9d | |
Robbie Averill | 27a40c6210 | |
Dylan Wagstaff | fe2aed7e58 | |
Robbie Averill | 4c65d66931 | |
Robbie Averill | b826f232c4 | |
Robbie Averill | 21d8212807 | |
Dylan Wagstaff | 192a1c4c2b | |
JorisDebonnet | 0fd7971cd9 | |
Ingo Schommer | f69ee07ec0 | |
Robbie Averill | 059191d91e | |
Raissa North | 38ee7a76da | |
Raissa North | 46fde9a573 | |
Raissa North | 79e2958fad | |
Raissa North | 68ba83dd6d | |
Raissa North | 4513998f1e | |
Dylan Wagstaff | 1dda806f39 | |
Robbie Averill | 47eef922c7 | |
Daniel Hensby | 654f45292c | |
Robbie Averill | e38c6c3a87 | |
Robbie Averill | 88b1b10f61 | |
Damian Mooyman | 0a7b3f768d | |
Dylan Wagstaff | d09dbdd9f1 | |
Franco Springveldt | b4e9b6e5cb | |
Robbie Averill | 779b155ee0 | |
Franco Springveldt | 42c733061d | |
Robbie Averill | 05fcdb6f41 | |
Robbie Averill | 680411e2ac | |
Robbie Averill | a1ea0df540 | |
Robbie Averill | cef1e24f86 | |
Robbie Averill | 37dde110c9 | |
Robbie Averill | c5f0827c2e | |
Robbie Averill | a60f592598 | |
Simon Erkelens | b757c3dc6d | |
Robbie Averill | 5f8d2af0d1 | |
Robbie Averill | 27da2d6ab4 | |
James Ellis | ef3e6d45b6 | |
Daniel Hensby | d2467ac73a | |
Robbie Averill | 3e7f021de7 | |
Robbie Averill | 5cc9312a8d | |
Robbie Averill | 3d771d8179 | |
Robbie Averill | 4cd01b2c82 | |
Daniel Hensby | a25b052510 | |
Robbie Averill | 2af878f6fa | |
Robbie Averill | 5aa1ca9afb | |
Brett Tasker | 56ec1f42c6 | |
Daniel Hensby | e9880ca3e5 | |
Daniel Hensby | 3b4f757d6e | |
Daniel Hensby | b1a8445a75 | |
Daniel Hensby | cc58c0b741 | |
Daniel Hensby | 1b3f3b9c62 | |
Daniel Hensby | 8e61aeb62b | |
Damian Mooyman | df6e182dd2 | |
Damian Mooyman | 344cf73ccf | |
Damian Mooyman | 38d168bd01 | |
Will Rossiter | 9db26d69f0 | |
Christopher Pitt | 3ca9a32bb2 | |
Damian Mooyman | b4b4ca14e8 | |
Damian Mooyman | 858baaf526 | |
Damian Mooyman | 73bdcd9f7f | |
Ian Walls | 14e768ca32 | |
Damian Mooyman | ad6e97dacb | |
Damian Mooyman | 078b0f51f9 | |
Ingo Schommer | 84bbe9d153 | |
Tim Kung | 529960d485 | |
Damian Mooyman | 8d1cc403b9 | |
helpfulrobot | 405023a5fa | |
Daniel Hensby | 947d0f09e0 | |
Daniel Hensby | 965389ded9 | |
Daniel Hensby | 3495ecf726 | |
helpfulrobot | cfb204d152 | |
helpfulrobot | 4a606eee82 | |
helpfulrobot | 7ee2dcea0f | |
Daniel Hensby | 8e4f03a409 | |
Daniel Hensby | 220a1e7bf6 | |
Daniel Hensby | 9054db2d5b | |
Daniel Hensby | b13161e1cd | |
Daniel Hensby | 2b1d357b6e | |
helpfulrobot | df60023e1f | |
helpfulrobot | 2f002bcfb8 | |
helpfulrobot | ec51614ade | |
Damian Mooyman | ddef979901 | |
helpfulrobot | 10730a4c64 | |
helpfulrobot | bc7d2c55e9 | |
scott1702 | c1643a85fb | |
Daniel Hensby | 2ee8123494 | |
rasstislav | 46b0990bff | |
Damian Mooyman | e7fd668474 | |
Scott Hutchinson | 1f00c8df41 | |
Damian Mooyman | 961aa1832e | |
Damian Mooyman | 09ec50bf2d | |
Christopher Joe | da87f71a15 | |
Damian Mooyman | 9cbb11a884 | |
Daniel Hensby | c48a4cf582 | |
Damian Mooyman | 12947ae886 | |
Will Rossiter | 9c649f0b6c | |
Garion Herman | 9e62b91217 | |
Damian Mooyman | 747a801ba5 | |
Damian Mooyman | c7b211e585 | |
Sean Harvey | 4478e61390 | |
Damian Mooyman | c40d120b0d | |
Damian Mooyman | ae391bcfb2 | |
Will Rossiter | adbb4be14d | |
Will Rossiter | c1a8a83011 | |
Daniel Hensby | 0a219493b4 | |
Will Rossiter | 949ec2b359 | |
Will Rossiter | 05650e912d | |
Will Rossiter | 420a51bbb5 | |
Damian Mooyman | 9abe13fcb6 | |
Ingo Schommer | a9545bc842 | |
Will Rossiter | 74b7990058 | |
Ingo Schommer | 1c841b25e1 | |
Saophalkun Ponlu | 5598dd3517 | |
Will Rossiter | 59c70f297c |
|
@ -0,0 +1,17 @@
|
|||
# For more information about the properties used in this file,
|
||||
# please see the EditorConfig documentation:
|
||||
# http://editorconfig.org
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[{*.yml,package.json}]
|
||||
indent_size = 2
|
||||
|
||||
# The indent size used in the package.json file cannot be changed:
|
||||
# https://github.com/npm/npm/pull/3180#issuecomment-16336516
|
|
@ -0,0 +1,7 @@
|
|||
/tests export-ignore
|
||||
/docs export-ignore
|
||||
/.gitattributes export-ignore
|
||||
/.gitignore export-ignore
|
||||
/.travis.yml export-ignore
|
||||
/.scrutinizer.yml export-ignore
|
||||
/codecov.yml export-ignore
|
|
@ -0,0 +1,11 @@
|
|||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
name: CI
|
||||
uses: silverstripe/gha-ci/.github/workflows/ci.yml@v1
|
|
@ -0,0 +1,16 @@
|
|||
name: Dispatch CI
|
||||
|
||||
on:
|
||||
# At 11:10 AM UTC, only on Saturday and Sunday
|
||||
schedule:
|
||||
- cron: '10 11 * * 6,0'
|
||||
|
||||
jobs:
|
||||
dispatch-ci:
|
||||
name: Dispatch CI
|
||||
# Only run cron on the silverstripe account
|
||||
if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Dispatch CI
|
||||
uses: silverstripe/gha-dispatch-ci@v1
|
|
@ -0,0 +1,17 @@
|
|||
name: Keepalive
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
# The 4th of every month at 10:50am UTC
|
||||
schedule:
|
||||
- cron: '50 10 4 * *'
|
||||
|
||||
jobs:
|
||||
keepalive:
|
||||
name: Keepalive
|
||||
# Only run cron on the silverstripe account
|
||||
if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Keepalive
|
||||
uses: silverstripe/gha-keepalive@v1
|
21
.travis.yml
21
.travis.yml
|
@ -1,21 +0,0 @@
|
|||
# See https://github.com/silverstripe-labs/silverstripe-travis-support for setup details
|
||||
|
||||
language: php
|
||||
php:
|
||||
- 5.3
|
||||
|
||||
env:
|
||||
- DB=MYSQL CORE_RELEASE=3.1
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- php: 5.4
|
||||
env: DB=MYSQL CORE_RELEASE=master
|
||||
|
||||
before_script:
|
||||
- git clone git://github.com/silverstripe-labs/silverstripe-travis-support.git ~/travis-support
|
||||
- php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss
|
||||
- cd ~/builds/ss
|
||||
|
||||
script:
|
||||
- phpunit userforms/tests/
|
|
@ -0,0 +1,9 @@
|
|||
[main]
|
||||
host = https://www.transifex.com
|
||||
|
||||
[o:silverstripe:p:silverstripe-spamprotection:r:master]
|
||||
file_filter = lang/<lang>.yml
|
||||
source_file = lang/en.yml
|
||||
source_lang = en
|
||||
type = YML
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
mappings:
|
||||
SpamProtector: SilverStripe\SpamProtection\SpamProtector
|
||||
CommentSpamProtection: SilverStripe\SpamProtection\Extension\CommentSpamProtection
|
||||
EditableSpamProtectionField: SilverStripe\SpamProtection\EditableSpamProtectionField
|
||||
FormSpamProtectionExtension: SilverStripe\SpamProtection\Extension\FormSpamProtectionExtension
|
||||
EditableSpamProtectionFieldTest: SilverStripe\SpamProtection\Tests\EditableSpamProtectionFieldTest
|
||||
EditableSpamProtectionFieldTest_Protector: SilverStripe\SpamProtection\Tests\Stub\Protector
|
||||
FormSpamProtectionExtensionTest: SilverStripe\SpamProtection\Tests\FormSpamProtectionExtensionTest
|
||||
FormSpamProtectionExtensionTest_BarProtector: SilverStripe\SpamProtection\Tests\Stub\BarProtector
|
||||
FormSpamProtectionExtensionTest_BazProtector: SilverStripe\SpamProtection\Tests\Stub\BazProtector
|
||||
FormSpamProtectionExtensionTest_FooProtector: SilverStripe\SpamProtection\Tests\Stub\FooProtector
|
17
LICENSE
17
LICENSE
|
@ -1,17 +0,0 @@
|
|||
Copyright (c) 2010-2013, SilverStripe Limited - www.silverstripe.com
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of SilverStripe nor the names of its contributors may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
156
README.md
156
README.md
|
@ -1,7 +1,7 @@
|
|||
# SpamProtection Module
|
||||
|
||||
[![Build Status](https://secure.travis-ci.org/silverstripe/silverstripe-spamprotection.png?branch=master)](http://travis-ci.org/silverstripe/silverstripe-spamprotection)
|
||||
|
||||
[![CI](https://github.com/silverstripe/silverstripe-spamprotection/actions/workflows/ci.yml/badge.svg)](https://github.com/silverstripe/silverstripe-spamprotection/actions/workflows/ci.yml)
|
||||
[![Silverstripe supported module](https://img.shields.io/badge/silverstripe-supported-0071C4.svg)](https://www.silverstripe.org/software/addons/silverstripe-commercially-supported-module-list/)
|
||||
|
||||
## Maintainer Contact
|
||||
|
||||
|
@ -13,114 +13,138 @@
|
|||
|
||||
## Requirements
|
||||
|
||||
SilverStripe 3.0.0 or greater
|
||||
Silverstripe 4.0+
|
||||
|
||||
**Note:** For Silverstripe 3.x, please use the [2.x release line](https://github.com/silverstripe/silverstripe-spamprotection/tree/2.0).
|
||||
|
||||
## Install
|
||||
|
||||
To install run `composer require silverstripe/spamprotection`.
|
||||
|
||||
## Documentation
|
||||
|
||||
This module provides a generic, consistent API for adding spam protection to
|
||||
your SilverStripe Forms. This does not provide any spam protection out of the
|
||||
box, for that, you must also download one of the spam protection
|
||||
This module provides a generic, consistent API for adding spam protection to
|
||||
your Silverstripe Forms. This does not provide any spam protection out of the
|
||||
box. For that, you must also download one of the spam protection
|
||||
implementations. Currently available options are:
|
||||
|
||||
* [Mollom](https://github.com/silverstripe/silverstripe-mollom)
|
||||
* [Recaptcha](https://github.com/chillu/silverstripe-recaptcha)
|
||||
* reCAPTCHA v2 (two implementations: [one](https://github.com/chillu/silverstripe-recaptcha), [two](https://github.com/UndefinedOffset/silverstripe-nocaptcha))
|
||||
* [MathSpamProtection](https://github.com/silverstripe/silverstripe-mathspamprotection)
|
||||
* [Akismet](https://github.com/tractorcow/silverstripe-akismet)
|
||||
* [Akismet](https://github.com/silverstripe/silverstripe-akismet)
|
||||
* [Mollom](https://github.com/silverstripe-archive/silverstripe-mollom)
|
||||
|
||||
As a developer you can also provide your own protector by creating a class which
|
||||
implements the `SpamProtector` interface. More on that below.
|
||||
implements the `\SilverStripe\SpamProtection\SpamProtector` interface. More on that below.
|
||||
|
||||
## Configuring
|
||||
|
||||
After installing this module and a protector of your choice (i.e mollom) you'll
|
||||
need to rebuild your database through `dev/build` and set the default protector
|
||||
After installing this module and a protector of your choice (i.e mollom) you'll
|
||||
need to rebuild your database through `dev/build` and set the default protector
|
||||
via SilverStripe's config system. This will update any Form instances that have
|
||||
spam protection hooks with that protector.
|
||||
|
||||
*mysite/_config/spamprotection.yml*
|
||||
|
||||
---
|
||||
name: spamprotection
|
||||
---
|
||||
FormSpamProtectionExtension:
|
||||
default_spam_protector: MollomSpamProtector
|
||||
```yaml
|
||||
---
|
||||
name: mycustomspamprotection
|
||||
---
|
||||
SilverStripe\SpamProtection\Extension\FormSpamProtectionExtension:
|
||||
default_spam_protector: MollomSpamProtector
|
||||
```
|
||||
|
||||
To add spam protection to your form instance call `enableSpamProtection`.
|
||||
|
||||
// your existing form code
|
||||
$form = new Form( .. );
|
||||
$form->enableSpamProtection();
|
||||
|
||||
The logic to perform the actual spam validation is controlled by each of the
|
||||
individual `SpamProtector` implementation since they each require a different
|
||||
```php
|
||||
// your existing form code
|
||||
$form = new Form(/* .. */);
|
||||
$form->enableSpamProtection();
|
||||
```
|
||||
|
||||
The logic to perform the actual spam validation is controlled by each of the
|
||||
individual `SpamProtector` implementations since they each require a different
|
||||
implementation client side or server side.
|
||||
|
||||
### Options
|
||||
|
||||
`enableSpamProtection` takes a hash of optional configuration values.
|
||||
`enableSpamProtection` takes a hash of optional configuration values.
|
||||
|
||||
$form->enableSpamProtection(array(
|
||||
'protector' => 'MathSpamProtector',
|
||||
'name' => 'Captcha'
|
||||
));
|
||||
```php
|
||||
$form->enableSpamProtection(array(
|
||||
'protector' => MathSpamProtector::class,
|
||||
'name' => 'Captcha'
|
||||
));
|
||||
```
|
||||
|
||||
Options to configure are:
|
||||
|
||||
*`protector`* a class name string or class instance which implements
|
||||
`SpamProtector`. Defaults to your
|
||||
`FormSpamProtectionExtension.default_spam_protector` value.
|
||||
* `protector`: a class name string or class instance which implements
|
||||
`\SilverStripe\SpamProtection\SpamProtector`. Defaults to your
|
||||
`SilverStripe\SpamProtection\Extension\FormSpamProtectionExtension.default_spam_protector` value.
|
||||
|
||||
*`name`* the form field name argument for the Captcha. Defaults to `Catcha`.
|
||||
*`title`* title of the Captcha form field. Defaults to `''`
|
||||
*`insertBefore`* name of existing field to insert the spam protection field prior to
|
||||
*`mapping`* an array mapping of the Form fields to the standardized list of
|
||||
field names. The list of standardized fields to pass to the spam protector are:
|
||||
* `name`: the form field name argument for the Captcha. Defaults to `Captcha`.
|
||||
* `title`: title of the Captcha form field. Defaults to `''`
|
||||
* `insertBefore`: name of existing field to insert the spam protection field prior to
|
||||
* `mapping`: an array mapping of the Form fields to the standardised list of
|
||||
field names. The list of standardised fields to pass to the spam protector are:
|
||||
|
||||
title
|
||||
body
|
||||
contextUrl
|
||||
contextTitle
|
||||
authorName
|
||||
authorMail
|
||||
authorUrl
|
||||
authorIp
|
||||
authorId
|
||||
```
|
||||
title
|
||||
body
|
||||
contextUrl
|
||||
contextTitle
|
||||
authorName
|
||||
authorMail
|
||||
authorUrl
|
||||
authorIp
|
||||
authorId
|
||||
```
|
||||
|
||||
## Defining your own `SpamProtector`
|
||||
|
||||
Any class that implements `SpamProtector` and the `getFormField()` method can
|
||||
be set as the spam protector. The `getFormField()` method returns the
|
||||
Any class that implements `\SilverStripe\SpamProtection\SpamProtector` and the `getFormField()` method can
|
||||
be set as the spam protector. The `getFormField()` method returns the
|
||||
`FormField` to be inserted into the `Form`. The `FormField` returned should be
|
||||
in charge of the validation process.
|
||||
|
||||
<?php
|
||||
```php
|
||||
<?php
|
||||
|
||||
class CustomSpamProtector implements SpamProtector {
|
||||
use CaptchaField;
|
||||
use SilverStripe\SpamProtection\SpamProtector;
|
||||
|
||||
public function getFormField($name = null, $title = null, $value = null) {
|
||||
// CaptchaField is a imagined class which has some functionality.
|
||||
// See silverstripe-mollom module for an example.
|
||||
return new CaptchaField($name, $title, $value);
|
||||
}
|
||||
class CustomSpamProtector implements SpamProtector
|
||||
{
|
||||
public function getFormField($name = null, $title = null, $value = null)
|
||||
{
|
||||
// CaptchaField is an imagined class which has some functionality.
|
||||
// See silverstripe-mollom module for an example.
|
||||
return new CaptchaField($name, $title, $value);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## Using Spam Protection with User Forms
|
||||
|
||||
This module provides an EditableSpamProtectionField wrapper which you can add
|
||||
to your UserForm instances. After installing this module and running /dev/build
|
||||
to rebuild the database, your Form Builder interface will have an option for
|
||||
`Spam Protection Field`. The type of spam protection used will be based on your
|
||||
This module provides an `EditableSpamProtectionField` wrapper which you can add
|
||||
to your UserForm instances. After installing this module and running `/dev/build`
|
||||
to rebuild the database, your Form Builder interface will have an option for
|
||||
`Spam Protection Field`. The type of spam protection used will be based on your
|
||||
currently selected SpamProtector instance.
|
||||
|
||||
## Releasing code with Spam Protection support
|
||||
|
||||
Spam protection is useful to provide but in some cases we do not want to require
|
||||
the developer to use spam protection. In that case, modules can provide the
|
||||
following pattern
|
||||
Spam protection is useful to provide but in some cases we do not want to require
|
||||
the developer to use spam protection. In that case, modules can provide the
|
||||
following pattern:
|
||||
|
||||
$form = new Form(..);
|
||||
```php
|
||||
use SilverStripe\Forms\Form;
|
||||
use SilverStripe\SpamProtection\Extension\FormSpamProtectionExtension;
|
||||
|
||||
if($form->hasExtension('FormSpamProtectionExtension')) {
|
||||
$form->enableSpamProtection();
|
||||
}
|
||||
$form = new Form(/* .. */);
|
||||
|
||||
if ($form->hasExtension(FormSpamProtectionExtension::class)) {
|
||||
$form->enableSpamProtection();
|
||||
}
|
||||
```
|
||||
|
|
11
_config.php
11
_config.php
|
@ -1,11 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Default configuration settings for the Spam Protection module.
|
||||
*
|
||||
* You should not put your own configuration in here rather use your
|
||||
* mysite/_config.php file
|
||||
*
|
||||
* @package spamprotection
|
||||
*/
|
||||
Deprecation::notification_version('1.1', 'spamprotection');
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
name: spamprotection
|
||||
Name: spamprotection
|
||||
---
|
||||
Form:
|
||||
SilverStripe\Forms\Form:
|
||||
extensions:
|
||||
- FormSpamProtectionExtension
|
||||
- SilverStripe\SpamProtection\Extension\FormSpamProtectionExtension
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [2.0.4]
|
||||
|
||||
* Set Form for formField when validating
|
||||
* Update translations.
|
||||
|
||||
## [2.0.3]
|
||||
|
||||
* Fix validateField method on EditableSpamProtectionField to use correct error message
|
||||
* Converted to PSR-2
|
||||
* Added standard Scrutinizer config
|
||||
* Added standard code of conduct
|
||||
* Added standard editor config
|
||||
* Added standard Travis config
|
||||
* Added standard license
|
||||
* Added license to composer.json
|
||||
* Added standard git attributes
|
||||
|
||||
## [2.0.2]
|
||||
|
||||
* Changelog added.
|
||||
* Create sk.yml
|
||||
* Update translations
|
||||
* Add tests for php 5.6 and framework 3.2
|
||||
* Fix for compatibility with userforms 3.0
|
|
@ -0,0 +1 @@
|
|||
When having discussions about this module in issues or pull request please adhere to the [SilverStripe Community Code of Conduct](https://docs.silverstripe.org/en/contributing/code_of_conduct).
|
|
@ -1,121 +1,284 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\SpamProtection;
|
||||
|
||||
use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Core\Manifest\ModuleLoader;
|
||||
use SilverStripe\Forms\DropdownField;
|
||||
use SilverStripe\Forms\FieldGroup;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\ORM\DataList;
|
||||
use SilverStripe\ORM\UnsavedRelationList;
|
||||
use SilverStripe\SpamProtection\Extension\FormSpamProtectionExtension;
|
||||
use SilverStripe\UserForms\Model\EditableFormField;
|
||||
use SilverStripe\UserForms\Model\EditableFormField\EditableEmailField;
|
||||
use SilverStripe\UserForms\Model\EditableFormField\EditableNumericField;
|
||||
use SilverStripe\UserForms\Model\EditableFormField\EditableTextField;
|
||||
|
||||
if (!class_exists(EditableFormField::class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Editable Spam Protecter Field. Used with the User Defined Forms module (if
|
||||
* Editable Spam Protecter Field. Used with the User Defined Forms module (if
|
||||
* installed) to allow the user to have captcha fields with their custom forms
|
||||
*
|
||||
*
|
||||
* @package spamprotection
|
||||
*/
|
||||
if(class_exists('EditableFormField')) {
|
||||
|
||||
class EditableSpamProtectionField extends EditableFormField {
|
||||
|
||||
static $singular_name = 'Spam Protection Field';
|
||||
|
||||
static $plural_name = 'Spam Protection Fields';
|
||||
|
||||
/**
|
||||
* Fields to include spam detection for
|
||||
*
|
||||
* @var array
|
||||
* @config
|
||||
*/
|
||||
private static $check_fields = array(
|
||||
'EditableEmailField',
|
||||
'EditableTextField',
|
||||
'EditableNumericField'
|
||||
);
|
||||
|
||||
public function getFormField() {
|
||||
|
||||
// Get protector
|
||||
$protector = FormSpamProtectionExtension::get_protector();
|
||||
if(empty($protector)) return false;
|
||||
|
||||
// Extract saved field mappings and update this field.
|
||||
$fieldMapping = array();
|
||||
foreach($this->getCandidateFields() as $otherField) {
|
||||
$mapSetting = "Map-{$otherField->Name}";
|
||||
$spamField = $this->getSetting($mapSetting);
|
||||
$fieldMapping[$otherField->Name] = $spamField;
|
||||
}
|
||||
$protector->setFieldMapping($fieldMapping);
|
||||
class EditableSpamProtectionField extends EditableFormField
|
||||
{
|
||||
private static $singular_name = 'Spam Protection Field';
|
||||
|
||||
// Generate field
|
||||
return $protector->getFormField($this->Name, $this->Title, null);
|
||||
}
|
||||
private static $plural_name = 'Spam Protection Fields';
|
||||
|
||||
/**
|
||||
* Gets the list of all candidate spam detectable fields on this field's form
|
||||
*
|
||||
* @return DataList
|
||||
*/
|
||||
protected function getCandidateFields() {
|
||||
private static $table_name = 'EditableSpamProtectionField';
|
||||
|
||||
// Get list of all configured classes available for spam detection
|
||||
$types = self::config()->check_fields;
|
||||
$typesInherit = array();
|
||||
foreach ($types as $type) {
|
||||
$subTypes = ClassInfo::subclassesFor($type);
|
||||
$typesInherit = array_merge($typesInherit, $subTypes);
|
||||
}
|
||||
/**
|
||||
* Fields to include spam detection for
|
||||
*
|
||||
* @var array
|
||||
* @config
|
||||
*/
|
||||
private static $check_fields = array(
|
||||
EditableEmailField::class,
|
||||
EditableTextField::class,
|
||||
EditableNumericField::class
|
||||
);
|
||||
|
||||
// Get all candidates of the above types
|
||||
return $this
|
||||
->Parent()
|
||||
->Fields()
|
||||
->filter('ClassName', $typesInherit)
|
||||
->exclude('Title', ''); // Ignore this field and those without titles
|
||||
}
|
||||
private static $db = array(
|
||||
'SpamFieldSettings' => 'Text'
|
||||
);
|
||||
|
||||
public function getFieldConfiguration() {
|
||||
$fields = parent::getFieldConfiguration();
|
||||
/**
|
||||
* @var FormField
|
||||
*/
|
||||
protected $formField = null;
|
||||
|
||||
// Get protector
|
||||
$protector = FormSpamProtectionExtension::get_protector();
|
||||
if (empty($protector)) return fields;
|
||||
|
||||
// Each other text field in this group can be assigned a field mapping
|
||||
$mapGroup = FieldGroup::create(_t(
|
||||
'EditableSpamProtectionField.SPAMFIELDMAPPING',
|
||||
'Spam Field Mapping'
|
||||
))->setDescription(_t(
|
||||
'EditableSpamProtectionField.SPAMFIELDMAPPINGDESCRIPTION',
|
||||
'Select the form fields that correspond to any relevant spam protection identifiers'
|
||||
));
|
||||
public function getFormField()
|
||||
{
|
||||
if ($this->formField) {
|
||||
return $this->formField;
|
||||
}
|
||||
|
||||
// Generate field specific settings
|
||||
$mappableFields = Config::inst()->get('FormSpamProtectionExtension', 'mappable_fields');
|
||||
$mappableFieldsMerged = array_combine($mappableFields, $mappableFields);
|
||||
foreach ($this->getCandidateFields() as $otherField) {
|
||||
$mapSetting = "Map-{$otherField->Name}";
|
||||
$fieldOption = DropdownField::create(
|
||||
$this->getSettingName($mapSetting),
|
||||
$otherField->Title,
|
||||
$mappableFieldsMerged,
|
||||
$this->getSetting($mapSetting)
|
||||
)->setEmptyString('');
|
||||
$mapGroup->push($fieldOption);
|
||||
}
|
||||
$fields->insertBefore($mapGroup, $this->getSettingName('ExtraClass'));
|
||||
// Get protector
|
||||
$protector = FormSpamProtectionExtension::get_protector();
|
||||
if (!$protector) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
// Extract saved field mappings and update this field.
|
||||
$fieldMapping = array();
|
||||
foreach ($this->getCandidateFields() as $otherField) {
|
||||
$mapSetting = "Map-{$otherField->Name}";
|
||||
$spamField = $this->spamMapValue($mapSetting);
|
||||
$fieldMapping[$otherField->Name] = $spamField;
|
||||
}
|
||||
$protector->setFieldMapping($fieldMapping);
|
||||
|
||||
public function getFieldValidationOptions() {
|
||||
return new FieldList();
|
||||
}
|
||||
|
||||
public function getRequired() {
|
||||
return false;
|
||||
}
|
||||
// Generate field
|
||||
$field = $protector->getFormField($this->Name, $this->Title, null);
|
||||
|
||||
public function getIcon() {
|
||||
return 'spamprotection/images/' . strtolower($this->class) . '.png';
|
||||
}
|
||||
|
||||
public function showInReports() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$this->doUpdateFormField($field);
|
||||
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FormField $field
|
||||
* @return self
|
||||
*/
|
||||
public function setFormField(FormField $field)
|
||||
{
|
||||
$this->formField = $field;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of all candidate spam detectable fields on this field's form
|
||||
*
|
||||
* @return DataList
|
||||
*/
|
||||
protected function getCandidateFields()
|
||||
{
|
||||
|
||||
// Get list of all configured classes available for spam detection
|
||||
$types = $this->config()->get('check_fields');
|
||||
$typesInherit = array();
|
||||
foreach ($types as $type) {
|
||||
$subTypes = ClassInfo::subclassesFor($type);
|
||||
$typesInherit = array_merge($typesInherit, $subTypes);
|
||||
}
|
||||
|
||||
// Get all candidates of the above types
|
||||
$parent = $this->Parent();
|
||||
if (!$parent) {
|
||||
return DataList::create(EditableFormField::class);
|
||||
}
|
||||
return $parent
|
||||
->Fields()
|
||||
->filter('ClassName', $typesInherit)
|
||||
->exclude('Title', ''); // Ignore this field and those without titles
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the spam field mapping values to a serialised DB field
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function onBeforeWrite()
|
||||
{
|
||||
$fieldMap = json_decode($this->SpamFieldSettings ?? '', true);
|
||||
if (empty($fieldMap)) {
|
||||
$fieldMap = array();
|
||||
}
|
||||
|
||||
foreach ($this->record as $key => $value) {
|
||||
if (substr($key ?? '', 0, 8) === 'spammap-') {
|
||||
$fieldMap[substr($key, 8)] = $value;
|
||||
}
|
||||
}
|
||||
$this->setField('SpamFieldSettings', json_encode($fieldMap));
|
||||
|
||||
return parent::onBeforeWrite();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in userforms 3.x and above
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getCMSFields()
|
||||
{
|
||||
/** @var FieldList $fields */
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
// Get protector
|
||||
$protector = FormSpamProtectionExtension::get_protector();
|
||||
if (!$protector) {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
if ($this->Parent()->Fields() instanceof UnsavedRelationList) {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
// Each other text field in this group can be assigned a field mapping
|
||||
$mapGroup = FieldGroup::create()
|
||||
->setTitle(_t(__CLASS__.'.SPAMFIELDMAPPING', 'Spam Field Mapping'))
|
||||
->setName('SpamFieldMapping')
|
||||
->setDescription(_t(
|
||||
__CLASS__.'.SPAMFIELDMAPPINGDESCRIPTION',
|
||||
'Select the form fields that correspond to any relevant spam protection identifiers'
|
||||
));
|
||||
|
||||
// Generate field specific settings
|
||||
$mappableFields = FormSpamProtectionExtension::config()->get('mappable_fields');
|
||||
$mappableFieldsMerged = array_combine($mappableFields ?? [], $mappableFields ?? []);
|
||||
foreach ($this->getCandidateFields() as $otherField) {
|
||||
$mapSetting = "Map-{$otherField->Name}";
|
||||
$fieldOption = DropdownField::create(
|
||||
'spammap-' . $mapSetting,
|
||||
$otherField->Title,
|
||||
$mappableFieldsMerged,
|
||||
$this->spamMapValue($mapSetting)
|
||||
)->setEmptyString('');
|
||||
$mapGroup->push($fieldOption);
|
||||
}
|
||||
$fields->addFieldToTab('Root.Main', $mapGroup);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to retrieve a value for the given spam field map name from the serialised data
|
||||
*
|
||||
* @param string $mapSetting
|
||||
* @return string
|
||||
*/
|
||||
public function spamMapValue($mapSetting)
|
||||
{
|
||||
$map = json_decode($this->SpamFieldSettings ?? '', true);
|
||||
if (empty($map)) {
|
||||
$map = array();
|
||||
}
|
||||
|
||||
if (array_key_exists($mapSetting, $map ?? [])) {
|
||||
return $map[$mapSetting];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Using custom validateField method
|
||||
* as Spam Protection Field implementations may have their own error messages
|
||||
* and may not be based on the field being required, e.g. Honeypot Field
|
||||
*
|
||||
* @param array $data
|
||||
* @param Form $form
|
||||
* @return void
|
||||
*/
|
||||
public function validateField($data, $form)
|
||||
{
|
||||
$formField = $this->getFormField();
|
||||
$formField->setForm($form);
|
||||
|
||||
if (isset($data[$this->Name])) {
|
||||
$formField->setValue($data[$this->Name]);
|
||||
}
|
||||
|
||||
$validator = $form->getValidator();
|
||||
if (!$formField->validate($validator)) {
|
||||
$errors = $validator->getErrors();
|
||||
$foundError = false;
|
||||
|
||||
// field validate implementation may not add error to validator
|
||||
if (count($errors ?? []) > 0) {
|
||||
// check if error already added from fields' validate method
|
||||
foreach ($errors as $error) {
|
||||
if ($error['fieldName'] == $this->Name) {
|
||||
$foundError = $error;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($foundError !== false) {
|
||||
// use error messaging already set from validate method
|
||||
$form->sessionMessage($foundError['message'], $foundError['messageType']);
|
||||
} else {
|
||||
// fallback to custom message set in CMS or default message if none set
|
||||
$form->sessionError($this->getErrorMessage()->HTML());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getFieldValidationOptions()
|
||||
{
|
||||
return FieldList::create();
|
||||
}
|
||||
|
||||
public function getRequired()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getIcon()
|
||||
{
|
||||
$resource = ModuleLoader::getModule('silverstripe/spamprotection')
|
||||
->getResource('images/editablespamprotectionfield.png');
|
||||
|
||||
if (!$resource->exists()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $resource->getURL();
|
||||
}
|
||||
|
||||
public function showInReports()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\SpamProtection\Extension;
|
||||
|
||||
use SilverStripe\Core\Extension;
|
||||
|
||||
/**
|
||||
* Apply the spam protection to the comments module if it is installed.
|
||||
*
|
||||
* @package spamprotection
|
||||
*/
|
||||
|
||||
class CommentSpamProtection extends Extension
|
||||
{
|
||||
public function alterCommentForm(&$form)
|
||||
{
|
||||
$form->enableSpamProtection(array(
|
||||
'name' => 'IsSpam',
|
||||
'mapping' => array(
|
||||
'Name' => 'authorName',
|
||||
'Email' => 'authorEmail',
|
||||
'URL' => 'authorUrl',
|
||||
'Comment' => 'body',
|
||||
'ReturnURL' => 'contextUrl'
|
||||
),
|
||||
'checks' => array(
|
||||
'spam',
|
||||
'profanity'
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\SpamProtection\Extension;
|
||||
|
||||
use LogicException;
|
||||
use SilverStripe\Core\Config\Configurable;
|
||||
use SilverStripe\Core\Extension;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
|
||||
/**
|
||||
* An extension to the {@link Form} class which provides the method
|
||||
* {@link enableSpamProtection()} helper.
|
||||
*
|
||||
* @package spamprotection
|
||||
*/
|
||||
|
||||
class FormSpamProtectionExtension extends Extension
|
||||
{
|
||||
use Configurable;
|
||||
|
||||
/**
|
||||
* @config
|
||||
*
|
||||
* The default spam protector class name to use. Class should implement the
|
||||
* {@link SpamProtector} interface.
|
||||
*
|
||||
* @var string $spam_protector
|
||||
*/
|
||||
private static $default_spam_protector;
|
||||
|
||||
/**
|
||||
* @config
|
||||
*
|
||||
* The {@link enableSpamProtection} method will define which of the form
|
||||
* values correlates to this form mapped fields list. Totally custom forms
|
||||
* and subclassed SpamProtector instances are define their own mapping
|
||||
*
|
||||
* @var array $mappable_fields
|
||||
*/
|
||||
private static $mappable_fields = array(
|
||||
'id',
|
||||
'title',
|
||||
'body',
|
||||
'contextUrl',
|
||||
'contextTitle',
|
||||
'authorName',
|
||||
'authorMail',
|
||||
'authorUrl',
|
||||
'authorIp',
|
||||
'authorId'
|
||||
);
|
||||
|
||||
/**
|
||||
* @config
|
||||
*
|
||||
* The field name to use for the {@link SpamProtector} {@link FormField}
|
||||
*
|
||||
* @var string $spam_protector
|
||||
*/
|
||||
private static $field_name = "Captcha";
|
||||
|
||||
/**
|
||||
* Instantiate a SpamProtector instance
|
||||
*
|
||||
* @param array $options Configuration options
|
||||
* @return SpamProtector|null
|
||||
*/
|
||||
public static function get_protector($options = null)
|
||||
{
|
||||
// generate the spam protector
|
||||
if (isset($options['protector'])) {
|
||||
$protector = $options['protector'];
|
||||
} else {
|
||||
$protector = self::config()->get('default_spam_protector');
|
||||
}
|
||||
|
||||
if ($protector && class_exists($protector ?? '')) {
|
||||
return Injector::inst()->create($protector);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates the spam protection module.
|
||||
*
|
||||
* @param array $options
|
||||
* @throws LogicException when get_protector method returns NULL.
|
||||
* @return Object
|
||||
*/
|
||||
public function enableSpamProtection($options = array())
|
||||
{
|
||||
|
||||
// captcha form field name (must be unique)
|
||||
if (isset($options['name'])) {
|
||||
$name = $options['name'];
|
||||
} else {
|
||||
$name = $this->config()->get('field_name');
|
||||
}
|
||||
|
||||
// captcha field title
|
||||
if (isset($options['title'])) {
|
||||
$title = $options['title'];
|
||||
} else {
|
||||
$title = '';
|
||||
}
|
||||
|
||||
// set custom mapping on this form
|
||||
$protector = self::get_protector($options);
|
||||
|
||||
if ($protector === null) {
|
||||
throw new LogicException('No spam protector has been set. Null is not valid value.');
|
||||
}
|
||||
|
||||
if ($protector && isset($options['mapping'])) {
|
||||
$protector->setFieldMapping($options['mapping']);
|
||||
}
|
||||
|
||||
if ($protector) {
|
||||
// add the form field
|
||||
if ($field = $protector->getFormField($name, $title)) {
|
||||
$field->setForm($this->owner);
|
||||
|
||||
// Add before field specified by insertBefore
|
||||
$inserted = false;
|
||||
if (!empty($options['insertBefore'])) {
|
||||
$inserted = $this->owner->Fields()->insertBefore($options['insertBefore'], $field);
|
||||
}
|
||||
if (!$inserted) {
|
||||
// Add field to end if not added already
|
||||
$this->owner->Fields()->push($field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->owner;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\SpamProtection;
|
||||
|
||||
use SilverStripe\Forms\FormField;
|
||||
|
||||
/**
|
||||
* SpamProtector base interface.
|
||||
*
|
||||
* All Protectors are required implement this interface if they want to appear
|
||||
* on the form.
|
||||
*
|
||||
* Classes with this interface are used to generate helper lists to allow the
|
||||
* user to select the protector.
|
||||
*
|
||||
* @package spamprotection
|
||||
*/
|
||||
|
||||
interface SpamProtector
|
||||
{
|
||||
/**
|
||||
* Return the {@link FormField} associated with this protector.
|
||||
*
|
||||
* Most spam methods will simply return a piece of HTML to be injected at
|
||||
* the end of the form. If a spam method needs to inject more than one
|
||||
* form field (i.e a hidden field and a text field) then return a
|
||||
* {@link FieldGroup} from this method to include both.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $title
|
||||
* @param mixed $value
|
||||
* @return FormField The resulting field
|
||||
*/
|
||||
public function getFormField($name = null, $title = null, $value = null);
|
||||
|
||||
/**
|
||||
* Set the fields to map spam protection too
|
||||
*
|
||||
* @param array $fieldMapping array of Field Names, where the indexes of the array are
|
||||
* the field names of the form and the values are the standard spamprotection
|
||||
* fields used by the protector
|
||||
*/
|
||||
public function setFieldMapping($fieldMapping);
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @package spamprotection
|
||||
*
|
||||
* @deprecated 1.0
|
||||
*/
|
||||
|
||||
class SpamProtectorManager {
|
||||
|
||||
private static $spam_protector = null;
|
||||
|
||||
public static function set_spam_protector($protector) {
|
||||
Deprecation::notice('1.1',
|
||||
'SpamProtectorManager::set_spam_protector() is deprecated. '.
|
||||
'Use the new config system. FormSpamProtectorExtension.default_spam_protector'
|
||||
);
|
||||
|
||||
self::$spam_protector = $protector;
|
||||
}
|
||||
|
||||
public static function get_spam_protector() {
|
||||
Deprecation::notice('1.1',
|
||||
'SpamProtectorManager::get_spam_protector() is deprecated'.
|
||||
'Use the new config system. FormSpamProtectorExtension.default_spam_protector');
|
||||
|
||||
return self::$spam_protector;
|
||||
}
|
||||
|
||||
public static function update_form($form, $before = null, $fieldsToSpamServiceMapping = array(), $title = null, $rightTitle = null) {
|
||||
Deprecation::notice('1.1',
|
||||
'SpamProtectorManager::update_form is deprecated'.
|
||||
'Please use $form->enableSpamProtection() for adding spamprotection'
|
||||
);
|
||||
|
||||
return $form->enableSpamProtection();
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Apply the spam protection to the comments module if it is installed.
|
||||
*
|
||||
* @package spamprotection
|
||||
*/
|
||||
|
||||
class CommentSpamProtection extends Extension {
|
||||
|
||||
public function alterCommentForm(&$form) {
|
||||
$form->enableSpamProtection(array(
|
||||
'mapping' => array(
|
||||
'Name' => 'authorName',
|
||||
'Email' => 'authorEmail',
|
||||
'URL' => 'authorUrl',
|
||||
'Comment' => 'body',
|
||||
'ReturnURL' => 'contextUrl'
|
||||
),
|
||||
'checks' => array(
|
||||
'spam',
|
||||
'profanity'
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* An extension to the {@link Form} class which provides the method
|
||||
* {@link enableSpamProtection()} helper.
|
||||
*
|
||||
* @package spamprotection
|
||||
*/
|
||||
|
||||
class FormSpamProtectionExtension extends Extension {
|
||||
|
||||
/**
|
||||
* @config
|
||||
*
|
||||
* The default spam protector class name to use. Class should implement the
|
||||
* {@link SpamProtector} interface.
|
||||
*
|
||||
* @var string $spam_protector
|
||||
*/
|
||||
private static $default_spam_protector;
|
||||
|
||||
/**
|
||||
* @config
|
||||
*
|
||||
* The {@link enableSpamProtection} method will define which of the form
|
||||
* values correlates to this form mapped fields list. Totally custom forms
|
||||
* and subclassed SpamProtector instances are define their own mapping
|
||||
*
|
||||
* @var array $mappable_fields
|
||||
*/
|
||||
private static $mappable_fields = array(
|
||||
'id',
|
||||
'title',
|
||||
'body',
|
||||
'contextUrl',
|
||||
'contextTitle',
|
||||
'authorName',
|
||||
'authorMail',
|
||||
'authorUrl',
|
||||
'authorIp',
|
||||
'authorId'
|
||||
);
|
||||
|
||||
/**
|
||||
* Instantiate a SpamProtector instance
|
||||
*
|
||||
* @param array $options Configuration options
|
||||
* @return SpamProtector
|
||||
*/
|
||||
public static function get_protector($options = null) {
|
||||
// generate the spam protector
|
||||
if(isset($options['protector'])) {
|
||||
$protector = $options['protector'];
|
||||
|
||||
if(is_string($protector)) {
|
||||
$protector = Injector::inst()->create($protector);
|
||||
}
|
||||
} else {
|
||||
$protector = Config::inst()->get('FormSpamProtectionExtension', 'default_spam_protector');
|
||||
$protector = Injector::inst()->create($protector);
|
||||
}
|
||||
return $protector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates the spam protection module.
|
||||
*
|
||||
* @param array $options
|
||||
*/
|
||||
public function enableSpamProtection($options = array()) {
|
||||
|
||||
// captcha form field name (must be unique)
|
||||
if(isset($options['name'])) {
|
||||
$name = $options['name'];
|
||||
} else {
|
||||
$name = 'Captcha';
|
||||
}
|
||||
|
||||
// captcha field title
|
||||
if(isset($options['title'])) {
|
||||
$title = $options['title'];
|
||||
} else {
|
||||
$title = '';
|
||||
}
|
||||
|
||||
// set custom mapping on this form
|
||||
$protector = self::get_protector($options);
|
||||
if(isset($options['mapping'])) {
|
||||
$protector->setFieldMapping($options['mapping']);
|
||||
}
|
||||
|
||||
// add the form field
|
||||
if($field = $protector->getFormField($name, $title)) {
|
||||
$field->setForm($this->owner);
|
||||
|
||||
// Add before field specified by insertBefore
|
||||
$inserted = false;
|
||||
if(!empty($options['insertBefore'])) {
|
||||
$inserted = $this->owner->Fields()->insertBefore($field, $options['insertBefore']);
|
||||
}
|
||||
if(!$inserted) {
|
||||
// Add field to end if not added already
|
||||
$this->owner->Fields()->push($field);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->owner;
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* SpamProtector base interface.
|
||||
*
|
||||
* All Protectors are required implement this interface if they want to appear
|
||||
* on the form.
|
||||
*
|
||||
* Classes with this interface are used to generate helper lists to allow the
|
||||
* user to select the protector.
|
||||
*
|
||||
* @package spamprotection
|
||||
*/
|
||||
|
||||
interface SpamProtector {
|
||||
|
||||
/**
|
||||
* Return the {@link FormField} associated with this protector.
|
||||
*
|
||||
* Most spam methods will simply return a piece of HTML to be injected at
|
||||
* the end of the form. If a spam method needs to inject more than one
|
||||
* form field (i.e a hidden field and a text field) then return a
|
||||
* {@link FieldGroup} from this method to include both.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $title
|
||||
* @param mixed $value
|
||||
* @return FormField The resulting field
|
||||
*/
|
||||
public function getFormField($name = null, $title = null, $value = null);
|
||||
|
||||
/**
|
||||
* Set the fields to map spam protection too
|
||||
*
|
||||
* @param array $fieldMapping array of Field Names, where the indexes of the array are
|
||||
* the field names of the form and the values are the standard spamprotection
|
||||
* fields used by the protector
|
||||
*/
|
||||
public function setFieldMapping($fieldMapping);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
comment: false
|
|
@ -1,16 +1,43 @@
|
|||
{
|
||||
"name": "silverstripe/spamprotection",
|
||||
"description": "Spam protection module for SilverStripe.",
|
||||
"type": "silverstripe-module",
|
||||
"keywords": ["silverstripe", "spamprotection"],
|
||||
"authors": [{
|
||||
"name": "Saophalkun Ponlu",
|
||||
"email": "phalkunz@silverstripe.com"
|
||||
}, {
|
||||
"name": "Will Rossiter",
|
||||
"email": "will@fullscreen.io"
|
||||
}],
|
||||
"require": {
|
||||
"silverstripe/framework": "~3.1"
|
||||
}
|
||||
}
|
||||
"name": "silverstripe/spamprotection",
|
||||
"description": "Spam protection module for SilverStripe.",
|
||||
"type": "silverstripe-vendormodule",
|
||||
"keywords": [
|
||||
"silverstripe",
|
||||
"spamprotection"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Saophalkun Ponlu",
|
||||
"email": "phalkunz@silverstripe.com"
|
||||
},
|
||||
{
|
||||
"name": "Will Rossiter",
|
||||
"email": "will@fullscreen.io"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^7.4 || ^8.0",
|
||||
"silverstripe/framework": "^4.10"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"silverstripe/versioned": "^1.0",
|
||||
"squizlabs/php_codesniffer": "^3.0",
|
||||
"silverstripe/userforms": "^5"
|
||||
},
|
||||
"extra": {
|
||||
"expose": [
|
||||
"images"
|
||||
]
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"SilverStripe\\SpamProtection\\": "code/",
|
||||
"SilverStripe\\SpamProtection\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"license": "BSD-3-Clause",
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
da:
|
||||
SilverStripe\SpamProtection\EditableSpamProtectionField:
|
||||
PLURALNAME: 'Spam beskyttelsefelter'
|
||||
PLURALS:
|
||||
one: 'Et spam beskyttelsefelt'
|
||||
other: '{count} Spambeskyttelsefelter'
|
||||
SINGULARNAME: 'Spam beskyttelsesfelt'
|
||||
SPAMFIELDMAPPING: 'Spam felt mapping'
|
||||
SPAMFIELDMAPPINGDESCRIPTION: 'Vælg de formfelter der matcher relevante spam beskyttelses identifikatorer'
|
|
@ -0,0 +1,9 @@
|
|||
de:
|
||||
SilverStripe\SpamProtection\EditableSpamProtectionField:
|
||||
PLURALNAME: Spamschutzfelder
|
||||
PLURALS:
|
||||
one: 'Ein Spamschutzfeld'
|
||||
other: '{count} Spamschutzfelder'
|
||||
SINGULARNAME: Spamschutzfeld
|
||||
SPAMFIELDMAPPING: 'Spamschutzfeld Zuordnung'
|
||||
SPAMFIELDMAPPINGDESCRIPTION: 'Wähle die Formularfelder, die mit Spamschutz verbunden sind'
|
|
@ -1,6 +1,10 @@
|
|||
en:
|
||||
EditableSpamProtectionField:
|
||||
SINGULARNAME: 'Spam Protection Field'
|
||||
SilverStripe\SpamProtection\EditableSpamProtectionField:
|
||||
PLURALNAME: 'Spam Protection Fields'
|
||||
PLURALS:
|
||||
one: 'A Spam Protection Field'
|
||||
other: '{count} Spam Protection Fields'
|
||||
SINGULARNAME: 'Spam Protection Field'
|
||||
SPAMFIELDMAPPING: 'Spam Field Mapping'
|
||||
SPAMFIELDMAPPINGDESCRIPTION: 'Select the form fields that correspond to any relevant spam protection identifiers'
|
||||
db_SpamFieldSettings: 'Spam field settings'
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
eo:
|
||||
SilverStripe\SpamProtection\EditableSpamProtectionField:
|
||||
PLURALNAME: 'Spamprotektaj kampoj'
|
||||
PLURALS:
|
||||
one: 'Unu spamprotekta kampo'
|
||||
other: '{count} spamprotektaj kampoj'
|
||||
SINGULARNAME: 'Spamprotekta kampo'
|
||||
SPAMFIELDMAPPING: 'Spamkampa mapigo'
|
||||
SPAMFIELDMAPPINGDESCRIPTION: 'Elektu la kampojn kiuj rilatas al eventualaj rilataj spamprotektaj identigiloj'
|
||||
db_SpamFieldSettings: 'Spamkampaj agordoj'
|
|
@ -0,0 +1,6 @@
|
|||
es:
|
||||
SilverStripe\SpamProtection\EditableSpamProtectionField:
|
||||
PLURALNAME: 'Campos de protección de spam'
|
||||
SINGULARNAME: 'Campo de protección de spam'
|
||||
SPAMFIELDMAPPING: 'Mapeo del campo spam'
|
||||
SPAMFIELDMAPPINGDESCRIPTION: 'Seleccionar los campos del formulario que corresponden a cualquier identificador de protección de spam relevante'
|
|
@ -0,0 +1,6 @@
|
|||
fa_IR:
|
||||
SilverStripe\SpamProtection\EditableSpamProtectionField:
|
||||
PLURALNAME: 'فیلدهای محافظت از هرزنوشته'
|
||||
SINGULARNAME: 'فیلد محافظت از هرزنوشته'
|
||||
SPAMFIELDMAPPING: 'نقشهبرداری فیلد هرزنوشته'
|
||||
SPAMFIELDMAPPINGDESCRIPTION: 'فیلدهای فرم را مطابق با هریک از شناساییکنندههای محافظت از هرزنوشته انتخاب کنید'
|
|
@ -0,0 +1,9 @@
|
|||
fi:
|
||||
SilverStripe\SpamProtection\EditableSpamProtectionField:
|
||||
PLURALNAME: 'Roskapostisuojauksen kentät'
|
||||
PLURALS:
|
||||
one: 'Roskapostin suodatuskenttä'
|
||||
other: '{count} Roskapostin suodatuskenttää'
|
||||
SINGULARNAME: 'Roskapostisuojauksen kenttä'
|
||||
SPAMFIELDMAPPING: 'Roskapostikentän kuvaus'
|
||||
SPAMFIELDMAPPINGDESCRIPTION: 'Valitse lomakekenttä, joka vastaa mitä tahansa oleellista roskapostisuodatuksen tunnistetta'
|
|
@ -0,0 +1,9 @@
|
|||
fi_FI:
|
||||
SilverStripe\SpamProtection\EditableSpamProtectionField:
|
||||
PLURALNAME: 'Roskapostisuojauksen kentät'
|
||||
PLURALS:
|
||||
one: 'Roskapostin suodatuskenttä'
|
||||
other: '{count} Roskapostin suodatuskenttää'
|
||||
SINGULARNAME: 'Roskapostisuojauksen kenttä'
|
||||
SPAMFIELDMAPPING: 'Roskapostikentän kuvaus'
|
||||
SPAMFIELDMAPPINGDESCRIPTION: 'Valitse lomakekenttä, joka vastaa mitä tahansa oleellista roskapostisuodatuksen tunnistetta'
|
|
@ -0,0 +1,6 @@
|
|||
hr:
|
||||
SilverStripe\SpamProtection\EditableSpamProtectionField:
|
||||
PLURALNAME: 'Polja Spam zaštite'
|
||||
SINGULARNAME: 'Polje Spam zaštite'
|
||||
SPAMFIELDMAPPING: 'Mapiranje polja Spama'
|
||||
SPAMFIELDMAPPINGDESCRIPTION: 'Odaberite polja forme koji odgovaraju relevantnim identifikatorima za zaštitu od spama'
|
|
@ -0,0 +1,10 @@
|
|||
it:
|
||||
SilverStripe\SpamProtection\EditableSpamProtectionField:
|
||||
PLURALNAME: 'Campi di Prevenzione Spam'
|
||||
PLURALS:
|
||||
many: '{count} Campi di Prevenzione Spam'
|
||||
one: 'Un Campo di Prevenzione Spam'
|
||||
other: '{count} Campi di Prevenzione Spam'
|
||||
SINGULARNAME: 'Campo di Prevenzione Spam'
|
||||
SPAMFIELDMAPPING: 'Mappatura Campo Spam'
|
||||
SPAMFIELDMAPPINGDESCRIPTION: 'Selezionare i campi della form che forniscono una qualche protezione dallo spam'
|
|
@ -0,0 +1,9 @@
|
|||
nl:
|
||||
SilverStripe\SpamProtection\EditableSpamProtectionField:
|
||||
PLURALNAME: 'Anti-spam velden'
|
||||
PLURALS:
|
||||
one: 'Een anti-spam veld'
|
||||
other: '{count} Anti-spam velden'
|
||||
SINGULARNAME: 'Anti-spam veld'
|
||||
SPAMFIELDMAPPING: 'Spam-velden koppelen'
|
||||
SPAMFIELDMAPPINGDESCRIPTION: 'Kies de velden die overeenkomen met de anti-spam identifiers'
|
|
@ -0,0 +1,6 @@
|
|||
ru:
|
||||
SilverStripe\SpamProtection\EditableSpamProtectionField:
|
||||
PLURALNAME: 'Поля защиты от спама'
|
||||
SINGULARNAME: 'Поле защиты от спама'
|
||||
SPAMFIELDMAPPING: 'Привязка полей для защиты от спама'
|
||||
SPAMFIELDMAPPINGDESCRIPTION: 'Выберите поля формы, которые соответствуют любому индентификатору защиты от спама'
|
|
@ -0,0 +1,12 @@
|
|||
sk:
|
||||
SilverStripe\SpamProtection\EditableSpamProtectionField:
|
||||
PLURALNAME: 'Polia ochrany proti spamu'
|
||||
PLURALS:
|
||||
few: '{count} polia ochrany proti spamu'
|
||||
many: '{count} polí ochrany proti spamu'
|
||||
one: 'Pole ochrany proti spamu'
|
||||
other: '{count} polí ochrany proti spamu'
|
||||
SINGULARNAME: 'Pole ochrany proti spamu'
|
||||
SPAMFIELDMAPPING: 'Mapovanie spamového poľa'
|
||||
SPAMFIELDMAPPINGDESCRIPTION: 'Vyberte polia formulára, ktoré zodpovedajú všetkým príslušným identifikátorom ochrany proti spamu'
|
||||
db_SpamFieldSettings: 'Nastavenia poľa spamu'
|
|
@ -0,0 +1,4 @@
|
|||
sl:
|
||||
SilverStripe\SpamProtection\EditableSpamProtectionField:
|
||||
PLURALNAME: 'Polja za zaščito pred neželeno pošto'
|
||||
SINGULARNAME: 'Polje za zaščito pred neželeno pošto'
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
Name: spamprotectionlegacy
|
||||
---
|
||||
SilverStripe\ORM\DatabaseAdmin:
|
||||
classname_value_remapping:
|
||||
EditableSpamProtectionField: 'SilverStripe\SpamProtection\EditableSpamProtectionField'
|
|
@ -0,0 +1,12 @@
|
|||
Copyright (c) 2017, SilverStripe Limited
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ruleset name="SilverStripe">
|
||||
<description>CodeSniffer ruleset for SilverStripe coding conventions.</description>
|
||||
|
||||
<file>code</file>
|
||||
<file>tests</file>
|
||||
|
||||
<rule ref="PSR2" >
|
||||
<!-- Current exclusions -->
|
||||
<exclude name="PSR1.Methods.CamelCapsMethodName" />
|
||||
<exclude name="PSR1.Files.SideEffects.FoundWithSymbols" />
|
||||
</rule>
|
||||
</ruleset>
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit bootstrap="vendor/silverstripe/framework/tests/bootstrap.php" colors="true">
|
||||
<testsuites>
|
||||
<testsuite name="Default">
|
||||
<directory>tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist addUncoveredFilesFromWhitelist="true">
|
||||
<directory suffix=".php">code/</directory>
|
||||
<exclude>
|
||||
<directory suffix=".php">tests/</directory>
|
||||
</exclude>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
|
@ -0,0 +1,178 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\SpamProtection\Tests;
|
||||
|
||||
use ReflectionClass;
|
||||
use SilverStripe\ORM\DataList;
|
||||
use SilverStripe\UserForms\Model\UserDefinedForm;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\Forms\FieldGroup;
|
||||
use SilverStripe\Forms\Form;
|
||||
use SilverStripe\Forms\RequiredFields;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use SilverStripe\SpamProtection\EditableSpamProtectionField;
|
||||
use SilverStripe\SpamProtection\Extension\FormSpamProtectionExtension;
|
||||
use SilverStripe\SpamProtection\Tests\Stub\Protector;
|
||||
|
||||
class EditableSpamProtectionFieldTest extends SapphireTest
|
||||
{
|
||||
protected $usesDatabase = true;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if (!class_exists(EditableSpamProtectionField::class)) {
|
||||
$this->markTestSkipped('"userforms" module not installed');
|
||||
}
|
||||
|
||||
Config::modify()->set(
|
||||
FormSpamProtectionExtension::class,
|
||||
'default_spam_protector',
|
||||
Protector::class
|
||||
);
|
||||
}
|
||||
|
||||
public function testValidateFieldDoesntAddErrorOnSuccess()
|
||||
{
|
||||
$formMock = $this->getFormMock();
|
||||
$formFieldMock = $this->getEditableFormFieldMock();
|
||||
|
||||
$formFieldMock
|
||||
->getFormField() // mock
|
||||
->expects($this->once())
|
||||
->method('validate')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$formMock
|
||||
->expects($this->never())
|
||||
->method('sessionMessage');
|
||||
|
||||
$formFieldMock->validateField(array('MyField' => null), $formMock);
|
||||
}
|
||||
|
||||
public function testValidateFieldAddsErrorFromField()
|
||||
{
|
||||
$formMock = $this->getFormMock();
|
||||
$formFieldMock = $this->getEditableFormFieldMock();
|
||||
|
||||
$formFieldMock
|
||||
->getFormField() // mock
|
||||
->expects($this->once())
|
||||
->method('validate')
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$formMock->getValidator()->validationError('MyField', 'some field message', 'required');
|
||||
|
||||
$formMock
|
||||
->expects($this->once())
|
||||
->method('sessionMessage')
|
||||
->with($this->stringContains('some field message'), $this->anything());
|
||||
|
||||
$formFieldMock->validateField(array('MyField' => null), $formMock);
|
||||
}
|
||||
|
||||
public function testValidateFieldAddsDefaultError()
|
||||
{
|
||||
$formMock = $this->getFormMock();
|
||||
$formFieldMock = $this->getEditableFormFieldMock();
|
||||
|
||||
$formFieldMock
|
||||
->getFormField() // mock
|
||||
->expects($this->once())
|
||||
->method('validate')
|
||||
->will($this->returnValue(false));
|
||||
|
||||
// field doesn't set any validation errors here
|
||||
|
||||
$formMock
|
||||
->expects($this->once())
|
||||
->method('sessionError')
|
||||
->with($this->stringContains('default error message'));
|
||||
|
||||
$formFieldMock->validateField(array('MyField' => null), $formMock);
|
||||
}
|
||||
|
||||
public function testSpamConfigurationShowsInCms()
|
||||
{
|
||||
$field = $this->getEditableFormFieldMock();
|
||||
$fields = $field->getCMSFields();
|
||||
|
||||
$this->assertInstanceOf(FieldGroup::class, $fields->fieldByName('Root.Main.SpamFieldMapping'));
|
||||
}
|
||||
|
||||
public function testSpamMapSettingsAreSerialised()
|
||||
{
|
||||
$field = $this->getEditableFormFieldMock();
|
||||
$field->SpamFieldSettings = json_encode(array('foo' => 'bar', 'bar' => 'baz'));
|
||||
$field->write();
|
||||
|
||||
$this->assertJson($field->SpamFieldSettings);
|
||||
$this->assertSame('bar', $field->spamMapValue('foo'));
|
||||
$this->assertSame('baz', $field->spamMapValue('bar'));
|
||||
}
|
||||
|
||||
public function testGetIcon()
|
||||
{
|
||||
$field = new EditableSpamProtectionField;
|
||||
|
||||
$this->assertStringContainsString('/images/editablespamprotectionfield.png', $field->getIcon());
|
||||
}
|
||||
|
||||
protected function getFormMock()
|
||||
{
|
||||
$formMock = $this->getMockBuilder(Form::class)
|
||||
->setMethods(['sessionMessage', 'sessionError', 'getValidator'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$formMock
|
||||
->expects($this->any())
|
||||
->method('getValidator')
|
||||
->will($this->returnValue(new RequiredFields()));
|
||||
|
||||
return $formMock;
|
||||
}
|
||||
|
||||
protected function getEditableFormFieldMock()
|
||||
{
|
||||
$page = new UserDefinedForm();
|
||||
$page->write();
|
||||
|
||||
$formFieldMock = $this->getMockBuilder(TextField::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$editableFormFieldMock = new EditableSpamProtectionField(array(
|
||||
'ParentID' => $page->ID,
|
||||
'ParentClass' => get_class($page),
|
||||
'Name' => 'MyField',
|
||||
'CustomErrorMessage' => 'default error message'
|
||||
));
|
||||
$editableFormFieldMock->write();
|
||||
$editableFormFieldMock->setFormField($formFieldMock);
|
||||
|
||||
return $editableFormFieldMock;
|
||||
}
|
||||
|
||||
public function testGetCandidateFieldsParentStatus()
|
||||
{
|
||||
$field = new EditableSpamProtectionField();
|
||||
$field->Name = 'MyField';
|
||||
$reflection = new ReflectionClass($field);
|
||||
$method = $reflection->getMethod('getCandidateFields');
|
||||
$method->setAccessible(true);
|
||||
// Assert with no parent
|
||||
$list = $method->invoke($field);
|
||||
$this->assertTrue($list instanceof DataList);
|
||||
// Assert with parent
|
||||
$page = new UserDefinedForm();
|
||||
$page->write();
|
||||
$field->ParentID = $page->ID;
|
||||
$field->ParentClass = get_class($page);
|
||||
$field->write();
|
||||
$list = $method->invoke($field);
|
||||
$this->assertTrue($list instanceof DataList);
|
||||
}
|
||||
}
|
|
@ -1,130 +1,142 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\SpamProtection\Tests;
|
||||
|
||||
use LogicException;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\Form;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use SilverStripe\SpamProtection\Extension\FormSpamProtectionExtension;
|
||||
use SilverStripe\SpamProtection\Tests\Stub\FooProtector;
|
||||
use SilverStripe\SpamProtection\Tests\Stub\BarProtector;
|
||||
use SilverStripe\SpamProtection\Tests\Stub\BazProtector;
|
||||
|
||||
/**
|
||||
* @package spamprotection
|
||||
*/
|
||||
class FormSpamProtectionExtensionTest extends SapphireTest {
|
||||
|
||||
protected $usesDatabase = false;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
class FormSpamProtectionExtensionTest extends SapphireTest
|
||||
{
|
||||
protected $usesDatabase = false;
|
||||
|
||||
$this->form = new Form($this, 'Form', new FieldList(
|
||||
new TextField('Title'),
|
||||
new TextField('Comment'),
|
||||
new TextField('URL')
|
||||
), new FieldList()
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @var Form
|
||||
*/
|
||||
protected $form = null;
|
||||
|
||||
public function testEnableSpamProtection() {
|
||||
Config::inst()->update(
|
||||
'FormSpamProtectionExtension', 'default_spam_protector',
|
||||
'FormSpamProtectionExtensionTest_FooProtector'
|
||||
);
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$form = $this->form->enableSpamProtection();
|
||||
$this->form = new Form(new Controller, 'Form', new FieldList(
|
||||
new TextField('Title'),
|
||||
new TextField('Comment'),
|
||||
new TextField('URL')
|
||||
), new FieldList());
|
||||
|
||||
$this->assertEquals('Foo', $form->Fields()->fieldByName('Captcha')->Title());
|
||||
$this->form->disableSecurityToken();
|
||||
}
|
||||
|
||||
}
|
||||
public function testEnableSpamProtectionThrowsException()
|
||||
{
|
||||
$this->expectException(LogicException::class);
|
||||
$this->expectExceptionMessage('No spam protector has been set. Null is not valid value.');
|
||||
|
||||
public function testEnableSpamProtectionCustomProtector() {
|
||||
$form = $this->form->enableSpamProtection(array(
|
||||
'protector' => 'FormSpamProtectionExtensionTest_BarProtector'
|
||||
));
|
||||
Config::modify()->set(FormSpamProtectionExtension::class, 'default_spam_protector', null);
|
||||
$this->form->enableSpamProtection();
|
||||
}
|
||||
|
||||
$this->assertEquals('Bar', $form->Fields()->fieldByName('Captcha')->Title());
|
||||
public function testEnableSpamProtection()
|
||||
{
|
||||
Config::modify()->set(
|
||||
FormSpamProtectionExtension::class,
|
||||
'default_spam_protector',
|
||||
FooProtector::class
|
||||
);
|
||||
|
||||
$protector = new FormSpamProtectionExtensionTest_BarProtector();
|
||||
$protector->title = "Baz";
|
||||
$form = $this->form->enableSpamProtection();
|
||||
|
||||
$form = $this->form->enableSpamProtection(array(
|
||||
'protector' => $protector
|
||||
));
|
||||
$this->assertEquals('Foo', $form->Fields()->fieldByName('Captcha')->Title());
|
||||
}
|
||||
|
||||
$this->assertEquals('Baz', $form->Fields()->fieldByName('Captcha')->Title());
|
||||
}
|
||||
public function testEnableSpamProtectionCustomProtector()
|
||||
{
|
||||
$form = $this->form->enableSpamProtection(array(
|
||||
'protector' => BarProtector::class
|
||||
));
|
||||
|
||||
public function testCustomOptions() {
|
||||
$form = $this->form->enableSpamProtection(array(
|
||||
'protector' => 'FormSpamProtectionExtensionTest_BazProtector',
|
||||
'title' => 'Qux',
|
||||
'name' => 'Borris'
|
||||
));
|
||||
$this->assertEquals('Bar', $form->Fields()->fieldByName('Captcha')->Title());
|
||||
}
|
||||
|
||||
$this->assertEquals('Qux', $form->Fields()->fieldByName('Borris')->Title());
|
||||
}
|
||||
|
||||
public function testInsertBefore() {
|
||||
|
||||
$form = $this->form->enableSpamProtection(array(
|
||||
'protector' => 'FormSpamProtectionExtensionTest_FooProtector',
|
||||
'insertBefore' => 'URL'
|
||||
));
|
||||
|
||||
$fields = $form->Fields();
|
||||
$this->assertEquals('Title', $fields[0]->Title());
|
||||
$this->assertEquals('Comment', $fields[1]->Title());
|
||||
$this->assertEquals('Foo', $fields[2]->Title());
|
||||
$this->assertEquals('URL', $fields[3]->Title());
|
||||
}
|
||||
|
||||
public function testInsertBeforeMissing() {
|
||||
|
||||
$form = $this->form->enableSpamProtection(array(
|
||||
'protector' => 'FormSpamProtectionExtensionTest_FooProtector',
|
||||
'insertBefore' => 'NotAField'
|
||||
));
|
||||
|
||||
// field should default to the end instead
|
||||
$fields = $form->Fields();
|
||||
$this->assertEquals('Title', $fields[0]->Title());
|
||||
$this->assertEquals('Comment', $fields[1]->Title());
|
||||
$this->assertEquals('URL', $fields[2]->Title());
|
||||
$this->assertEquals('Foo', $fields[3]->Title());
|
||||
}
|
||||
|
||||
public function testEnableSpamProtectionCustomTitle()
|
||||
{
|
||||
$form = $this->form->enableSpamProtection(array(
|
||||
'protector' => BarProtector::class,
|
||||
'title' => 'Baz',
|
||||
));
|
||||
|
||||
$this->assertEquals('Baz', $form->Fields()->fieldByName('Captcha')->Title());
|
||||
}
|
||||
|
||||
public function testCustomOptions()
|
||||
{
|
||||
$form = $this->form->enableSpamProtection(array(
|
||||
'protector' => BazProtector::class,
|
||||
'title' => 'Qux',
|
||||
'name' => 'Borris'
|
||||
));
|
||||
|
||||
$this->assertEquals('Qux', $form->Fields()->fieldByName('Borris')->Title());
|
||||
}
|
||||
|
||||
public function testConfigurableName()
|
||||
{
|
||||
$field_name = "test_configurable_name";
|
||||
Config::modify()->set(
|
||||
FormSpamProtectionExtension::class,
|
||||
'default_spam_protector',
|
||||
FooProtector::class
|
||||
);
|
||||
Config::modify()->set(
|
||||
FormSpamProtectionExtension::class,
|
||||
'field_name',
|
||||
$field_name
|
||||
);
|
||||
$form = $this->form->enableSpamProtection();
|
||||
// remove for subsequent tests
|
||||
Config::modify()->remove(FormSpamProtectionExtension::class, 'field_name');
|
||||
// field should take up configured name
|
||||
$this->assertEquals('Foo', $form->Fields()->fieldByName($field_name)->Title());
|
||||
}
|
||||
|
||||
public function testInsertBefore()
|
||||
{
|
||||
$form = $this->form->enableSpamProtection(array(
|
||||
'protector' => FooProtector::class,
|
||||
'insertBefore' => 'URL'
|
||||
));
|
||||
|
||||
$fields = $form->Fields();
|
||||
$this->assertEquals('Title', $fields[0]->Title());
|
||||
$this->assertEquals('Comment', $fields[1]->Title());
|
||||
$this->assertEquals('Foo', $fields[2]->Title());
|
||||
$this->assertEquals('URL', $fields[3]->Title());
|
||||
}
|
||||
|
||||
public function testInsertBeforeMissing()
|
||||
{
|
||||
$form = $this->form->enableSpamProtection(array(
|
||||
'protector' => FooProtector::class,
|
||||
'insertBefore' => 'NotAField'
|
||||
));
|
||||
|
||||
// field should default to the end instead
|
||||
$fields = $form->Fields();
|
||||
$this->assertEquals('Title', $fields[0]->Title());
|
||||
$this->assertEquals('Comment', $fields[1]->Title());
|
||||
$this->assertEquals('URL', $fields[2]->Title());
|
||||
$this->assertEquals('Foo', $fields[3]->Title());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @package spamprotection
|
||||
*/
|
||||
class FormSpamProtectionExtensionTest_BazProtector implements SpamProtector, TestOnly {
|
||||
|
||||
public function getFormField($name = null, $title = null, $value = null) {
|
||||
return new TextField($name, $title, $value);
|
||||
}
|
||||
|
||||
public function setFieldMapping($fieldMapping) {}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @package spamprotection
|
||||
*/
|
||||
class FormSpamProtectionExtensionTest_BarProtector implements SpamProtector, TestOnly {
|
||||
|
||||
public $title = 'Bar';
|
||||
|
||||
public function getFormField($name = null, $title = null, $value = null) {
|
||||
return new TextField($name, $this->title, $value);
|
||||
}
|
||||
|
||||
public function setFieldMapping($fieldMapping) {}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @package spamprotection
|
||||
*/
|
||||
class FormSpamProtectionExtensionTest_FooProtector implements SpamProtector, TestOnly {
|
||||
|
||||
public function getFormField($name = null, $title = null, $value = null) {
|
||||
return new TextField($name, 'Foo', $value);
|
||||
}
|
||||
|
||||
public function setFieldMapping($fieldMapping) {}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\SpamProtection\Tests\FormSpamProtectionExtensionTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use SilverStripe\SpamProtection\SpamProtector;
|
||||
|
||||
/**
|
||||
* @package spamprotection
|
||||
*/
|
||||
class BarProtector implements SpamProtector, TestOnly
|
||||
{
|
||||
public function getFormField($name = null, $title = null, $value = null)
|
||||
{
|
||||
$title = $title ?: 'Bar';
|
||||
return new TextField($name, $title, $value);
|
||||
}
|
||||
|
||||
public function setFieldMapping($fieldMapping)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\SpamProtection\Tests\FormSpamProtectionExtensionTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use SilverStripe\SpamProtection\SpamProtector;
|
||||
|
||||
/**
|
||||
* @package spamprotection
|
||||
*/
|
||||
class BazProtector implements SpamProtector, TestOnly
|
||||
{
|
||||
public function getFormField($name = null, $title = null, $value = null)
|
||||
{
|
||||
return new TextField($name, $title, $value);
|
||||
}
|
||||
|
||||
public function setFieldMapping($fieldMapping)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\SpamProtection\Tests\FormSpamProtectionExtensionTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use SilverStripe\SpamProtection\SpamProtector;
|
||||
|
||||
/**
|
||||
* @package spamprotection
|
||||
*/
|
||||
class FooProtector implements SpamProtector, TestOnly
|
||||
{
|
||||
public function getFormField($name = null, $title = null, $value = null)
|
||||
{
|
||||
return new TextField($name, 'Foo', $value);
|
||||
}
|
||||
|
||||
public function setFieldMapping($fieldMapping)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\SpamProtection\Tests\Stub;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use SilverStripe\SpamProtection\SpamProtector;
|
||||
|
||||
/**
|
||||
* @package spamprotection
|
||||
*/
|
||||
class BarProtector implements SpamProtector, TestOnly
|
||||
{
|
||||
public function getFormField($name = null, $title = null, $value = null)
|
||||
{
|
||||
$title = $title ?: 'Bar';
|
||||
return new TextField($name, $title, $value);
|
||||
}
|
||||
|
||||
public function setFieldMapping($fieldMapping)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\SpamProtection\Tests\Stub;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use SilverStripe\SpamProtection\SpamProtector;
|
||||
|
||||
/**
|
||||
* @package spamprotection
|
||||
*/
|
||||
class BazProtector implements SpamProtector, TestOnly
|
||||
{
|
||||
public function getFormField($name = null, $title = null, $value = null)
|
||||
{
|
||||
return new TextField($name, $title, $value);
|
||||
}
|
||||
|
||||
public function setFieldMapping($fieldMapping)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\SpamProtection\Tests\Stub;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use SilverStripe\SpamProtection\SpamProtector;
|
||||
|
||||
/**
|
||||
* @package spamprotection
|
||||
*/
|
||||
class FooProtector implements SpamProtector, TestOnly
|
||||
{
|
||||
public function getFormField($name = null, $title = null, $value = null)
|
||||
{
|
||||
return new TextField($name, 'Foo', $value);
|
||||
}
|
||||
|
||||
public function setFieldMapping($fieldMapping)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace SilverStripe\SpamProtection\Tests\Stub;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use SilverStripe\SpamProtection\SpamProtector;
|
||||
|
||||
class Protector implements SpamProtector, TestOnly
|
||||
{
|
||||
public function getFormField($name = null, $title = null, $value = null)
|
||||
{
|
||||
return new TextField($name, 'Foo', $value);
|
||||
}
|
||||
|
||||
public function setFieldMapping($fieldMapping)
|
||||
{
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue