From 9af974cd1a602c44113665ac2ef4fb3cd7189540 Mon Sep 17 00:00:00 2001 From: "James (DPC)" Date: Tue, 25 Jan 2022 09:52:50 +1100 Subject: [PATCH 1/9] Hide verification value in emails via a checkbox on the field. Provide tests to support. Provide a task to allow update of historical fields where the previous behaviour is required. --- _config/config.yml | 6 + composer.json | 12 +- docs/en/001_index.md | 26 ++- .../UserDefinedFormControllerExtension.php | 36 ++++ src/Models/EditableRecaptchaV3Field.php | 33 ++- src/Models/SubmittedRecaptchaV3Field.php | 33 +++ src/Tasks/IncludeInEmailsTask.php | 87 ++++++++ tests/.gitkeep | 0 tests/RecaptchaV3FieldFunctionalTest.php | 202 ++++++++++++++++++ tests/RecaptchaV3FieldFunctionalTest.yml | 50 +++++ tests/RecaptchaV3FieldTest.php | 42 ++++ 11 files changed, 522 insertions(+), 5 deletions(-) create mode 100644 _config/config.yml create mode 100644 src/Extensions/UserDefinedFormControllerExtension.php create mode 100644 src/Models/SubmittedRecaptchaV3Field.php create mode 100644 src/Tasks/IncludeInEmailsTask.php delete mode 100644 tests/.gitkeep create mode 100644 tests/RecaptchaV3FieldFunctionalTest.php create mode 100644 tests/RecaptchaV3FieldFunctionalTest.yml create mode 100644 tests/RecaptchaV3FieldTest.php diff --git a/_config/config.yml b/_config/config.yml new file mode 100644 index 0000000..b6ad7d1 --- /dev/null +++ b/_config/config.yml @@ -0,0 +1,6 @@ +--- +Name: nswdpc_recaptchav3_userforms +--- +SilverStripe\UserForms\Control\UserDefinedFormController: + extensions: + - 'NSWDPC\SpamProtection\UserDefinedFormControllerExtension' diff --git a/composer.json b/composer.json index 5934044..6c12fe4 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,17 @@ "silverstripe/userforms" : "^5" }, "require-dev": { - "phpunit/phpunit": "^5.7 | ^7", + "phpunit/phpunit": "^5.7", "squizlabs/php_codesniffer": "^3.0" + }, + "autoload": { + "psr-4": { + "NSWDPC\\SpamProtection\\Tests\\": [ + "tests/" + ], + "NSWDPC\\SpamProtection\\": [ + "src/" + ] + } } } diff --git a/docs/en/001_index.md b/docs/en/001_index.md index cf74d33..642cd39 100644 --- a/docs/en/001_index.md +++ b/docs/en/001_index.md @@ -13,6 +13,28 @@ reCAPTCHA returns a score between 0 and 1 based on visitor interaction with the + If you set the threshold to 100, all submissions on the form will be blocked + If you set the threshold to zero, all submissions will be allowed -### Action +### Custom action -This is a value used for analytics purposes in the [reCAPTCHA admin](https://www.google.com/recaptcha/admin/). +This is a value used for analytics purposes in the [reCAPTCHA admin](https://www.google.com/recaptcha/admin/). You can use this to track scores per-form. + +### Including the reCAPTCHAv3 verification value in email + +Before v0.1.2, the reCAPTCHAv3 verification information for the submitted form was included in all emails: + +```json +{"score":0.9,"hostname":"my.site","action":"\/some\/action"} +``` + +From v0.1.2, this is conditionally **excluded** by default for all emails recipients. + +The reCAPTCHAv3 action feature provides the ability to report per-action analytics (Set a custom action). + +Use the 'Include reCAPTCHAv3 verification information in emails' checkbox in the field settings to enable the value in emails. + +Submitted reCAPTCHAv3 verification values are always saved and can be viewed in the stored submissions, if enabled. + +Due to the way the userforms module includes email field data and merge fields, the reCAPTCHAv3 verification information value cannot currently be included on a per-recipient basis. + +> You are using > v0.1.2 if you can see the 'Include reCAPTCHAv3 verification information in emails' checkbox + +If you wish to retain the verification value in emails for historical fields, ask an administrator to run the 'IncludeInEmailsTask'. diff --git a/src/Extensions/UserDefinedFormControllerExtension.php b/src/Extensions/UserDefinedFormControllerExtension.php new file mode 100644 index 0000000..03e4516 --- /dev/null +++ b/src/Extensions/UserDefinedFormControllerExtension.php @@ -0,0 +1,36 @@ +getIncludeValueInEmails()) ) { + $emailData['Fields']->remove( $field ); + } + } + + } + +} diff --git a/src/Models/EditableRecaptchaV3Field.php b/src/Models/EditableRecaptchaV3Field.php index 0adc9ec..05b51f3 100644 --- a/src/Models/EditableRecaptchaV3Field.php +++ b/src/Models/EditableRecaptchaV3Field.php @@ -1,6 +1,7 @@ 'Int',// 0-100 - 'Action' => 'Varchar(255)'// custom action + 'Action' => 'Varchar(255)',// custom action + 'IncludeInEmails' => 'Boolean' ]; /** @@ -35,6 +37,7 @@ class EditableRecaptchaV3Field extends EditableFormField */ private static $defaults = [ 'Action' => 'submit', + 'IncludeInEmails' => 0 ]; /** @@ -43,6 +46,28 @@ class EditableRecaptchaV3Field extends EditableFormField */ private static $table_name = 'EditableRecaptchaV3Field'; + /** + * The reCAPTCHA verification value is always stored + * Use the IncludeInEmails value to determine whether the reCAPTCHA value is included in emails + * along with being saved to the submitted field + * @inheritdoc + */ + public function showInReports() + { + return true; + } + + /** + * Return the submitted field instance, with the IncludeInEmails value set as a boolean property + * @inheritdoc + */ + public function getSubmittedFormField() + { + $field = SubmittedRecaptchaV3Field::create(); + $field->setIncludeValueInEmails( $this->IncludeInEmails == 1 ); + return $field; + } + /** * Event handler called before writing to the database. */ @@ -131,7 +156,11 @@ public function getCMSFields() _t( 'NSWDPC\SpamProtection.RECAPTCHA_SETTINGS', 'reCAPTCHA v3 settings') ), $range_field, - RecaptchaV3SpamProtector::getActionField('Action', $this->Action) + RecaptchaV3SpamProtector::getActionField('Action', $this->Action), + CheckboxField::create( + 'IncludeInEmails', + _t( 'NSWDPC\SpamProtection.INCLUDE_IN_EMAILS', 'Include reCAPTCHAv3 verification information in emails') + ) ] ); return $fields; diff --git a/src/Models/SubmittedRecaptchaV3Field.php b/src/Models/SubmittedRecaptchaV3Field.php new file mode 100644 index 0000000..9921d41 --- /dev/null +++ b/src/Models/SubmittedRecaptchaV3Field.php @@ -0,0 +1,33 @@ +includeValueInEmails = $include; + return $this; + } + + /** + * Getter + */ + public function getIncludeValueInEmails() : bool { + return $this->includeValueInEmails; + } +} diff --git a/src/Tasks/IncludeInEmailsTask.php b/src/Tasks/IncludeInEmailsTask.php new file mode 100644 index 0000000..0b2afd6 --- /dev/null +++ b/src/Tasks/IncludeInEmailsTask.php @@ -0,0 +1,87 @@ +getVar('before'); + $publish = $request->getVar('publish') == 1; + + if(!$before) { + DB::alteration_message("You must provide a date/time as the 'before' param, to update all fields before that date/time. The value is anything understood by DateTime", "error"); + } + + try { + $dt = new \DateTime($before); + $beforeFormatted = $dt->format('Y-m-d'); + } catch(\Exception $e) { + DB::alteration_message("Could not understand the before value '{$before}'", "error");\ + return; + } + + $fields = EditableRecaptchaV3Field::get()->filter([ + 'Created:LessThan' => $beforeFormatted + ]); + + if($fields->count() == 0) { + DB::alteration_message("No fields found to change before {$beforeFormatted}", "noop"); + return; + } + + if(!$publish) { + DB::alteration_message("Provide publish=1 to change the published field as well", "noop"); + } + + foreach($fields as $field) { + try { + $field->IncludeInEmails = 1; + $field->write(); + DB::alteration_message("Changed field #{$field->ID} {$field->Title}", "changed"); + if($publish) { + $field->doPublish(); + DB::alteration_message("Published field #{$field->ID} {$field->Title}", "changed"); + } + } catch (\Exception $e) { + DB::alteration_message("Failed to change field #{$field->ID} {$field->Title}. Error:{$e->getMessage()}", "error"); + } + } + } + +} diff --git a/tests/.gitkeep b/tests/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/tests/RecaptchaV3FieldFunctionalTest.php b/tests/RecaptchaV3FieldFunctionalTest.php new file mode 100644 index 0000000..568d205 --- /dev/null +++ b/tests/RecaptchaV3FieldFunctionalTest.php @@ -0,0 +1,202 @@ +objFromFixture(UserDefinedForm::class, $fixtureName); + + $this->actWithPermission('ADMIN', function () use ($form) { + $form->publishRecursive(); + }); + + return $form; + } + + public function testProcessIncludeInEmails() + { + + $field = new TestRecaptchaV3Field('include_in_emails'); + $field->setIsSuccess(true); + + // use the test field + Injector::inst()->registerService( + $field, + RecaptchaV3Field::class + ); + + // and test verifier + Injector::inst()->registerService( + new TestVerifier(), Verifier::class + ); + + $userDefinedForm = $this->setupFormFrontend('include-in-emails'); + + $recipients = $userDefinedForm->EmailRecipients(); + $this->assertEquals(1, $recipients->count(), "UserDefinedForm has one EmailRecipient"); + + $recipient = $recipients->first(); + $this->assertEquals('test.include@example.com', $recipient->EmailAddress, "EmailRecipient has correct address"); + + $this->assertInstanceOf(UserDefinedForm::class, $userDefinedForm, "Form is a UserDefinedForm"); + + $controller = new UserDefinedFormController($userDefinedForm); + + $this->autoFollowRedirection = true; + $this->clearEmails(); + + // load the form + $page = $this->get( $userDefinedForm->Link() ); + + // check the form exists + $form = $controller->Form(); + + $captchaField = $form->HiddenFields()->fieldByName('include_in_emails'); + + $this->assertInstanceOf( TestRecaptchaV3Field::class, $captchaField, "include_in_emails is a TestRecaptchaV3Field" ); + + $data = []; + $response = $this->submitForm('UserForm_Form_' . $userDefinedForm->ID, null, $data); + + $submittedFields = SubmittedRecaptchaV3Field::get()->filter(['Name' => 'include_in_emails']); + + $this->assertTrue($submittedFields->count() == 1, "One SubmittedRecaptchaV3Field for include_in_emails"); + + $submittedField = $submittedFields->first(); + + $value = $submittedField->Value; + $title = $submittedField->Title; + + $this->assertNotEmpty( $value, "Submitted verification field value empty" ); + $this->assertNotEmpty( $title, "Submitted verification field title empty" ); + + $decodedValue = json_decode($value, true); + + $this->assertNotEmpty($decodedValue); + $this->assertEquals( TestVerifier::RESPONSE_HUMAN_SCORE, $decodedValue['score'], "Score is " . TestVerifier::RESPONSE_HUMAN_SCORE); + $this->assertEquals( 'localhost', $decodedValue['hostname'], "Hostname is localhost"); + $this->assertEquals( 'includeinemails/functionaltest', $decodedValue['action'], "Action is includeinemails/functionaltest"); + + $email = $this->findEmail( $recipient->EmailAddress, $recipient->EmailReplyTo, $recipient->EmailSubject ); + + // check emails + $this->assertEmailSent( $recipient->EmailAddress, $recipient->EmailReplyTo, $recipient->EmailSubject ); + + $this->assertTrue(strpos($email['Content'], $recipient->EmailBodyHtml) !== false, 'Email contains the expected HTML string'); + $this->assertTrue(strpos($email['Content'], $title) !== false, 'Email contains the field name'); + $this->assertTrue(strpos($email['Content'], $value) !== false, 'Email contains the field value'); + + } + + public function testProcessNotIncludeInEmails() { + $field = new TestRecaptchaV3Field('not_include_in_emails'); + $field->setIsSuccess(true); + + // use the test field + Injector::inst()->registerService( + $field, + RecaptchaV3Field::class + ); + + // and test verifier + Injector::inst()->registerService( + new TestVerifier(), Verifier::class + ); + + $userDefinedForm = $this->setupFormFrontend('not-include-in-emails'); + + $recipients = $userDefinedForm->EmailRecipients(); + $this->assertEquals(1, $recipients->count(), "UserDefinedForm has one EmailRecipient"); + + $recipient = $recipients->first(); + $this->assertEquals('test.notinclude@example.com', $recipient->EmailAddress, "EmailRecipient has correct address"); + + $this->assertInstanceOf(UserDefinedForm::class, $userDefinedForm, "Form is a UserDefinedForm"); + + $controller = new UserDefinedFormController($userDefinedForm); + + $this->autoFollowRedirection = true; + $this->clearEmails(); + + // load the form + $page = $this->get( $userDefinedForm->Link() ); + + // check the form exists + $form = $controller->Form(); + + $captchaField = $form->HiddenFields()->fieldByName('not_include_in_emails'); + + $this->assertInstanceOf( TestRecaptchaV3Field::class, $captchaField, "not_include_in_emails is a TestRecaptchaV3Field" ); + + $data = []; + $response = $this->submitForm('UserForm_Form_' . $userDefinedForm->ID, null, $data); + + $submittedFields = SubmittedRecaptchaV3Field::get()->filter(['Name' => 'not_include_in_emails']); + + $this->assertTrue($submittedFields->count() == 1, "One SubmittedRecaptchaV3Field for not_include_in_emails"); + + $submittedField = $submittedFields->first(); + + $value = $submittedField->Value; + $title = $submittedField->Title; + + $this->assertNotEmpty( $value, "Submitted verification field value empty" ); + $this->assertNotEmpty( $title, "Submitted verification field title empty" ); + + $decodedValue = json_decode($value, true); + + $this->assertNotEmpty($decodedValue); + $this->assertEquals( TestVerifier::RESPONSE_HUMAN_SCORE, $decodedValue['score'], "Score is " . TestVerifier::RESPONSE_HUMAN_SCORE); + $this->assertEquals( 'localhost', $decodedValue['hostname'], "Hostname is localhost"); + $this->assertEquals( 'notincludeinemails/functionaltest', $decodedValue['action'], "Action is notincludeinemails/functionaltest"); + + $email = $this->findEmail( $recipient->EmailAddress, $recipient->EmailReplyTo, $recipient->EmailSubject ); + + // check emails + $this->assertEmailSent( $recipient->EmailAddress, $recipient->EmailReplyTo, $recipient->EmailSubject ); + + $this->assertTrue(strpos($email['Content'], $recipient->EmailBodyHtml) !== false, 'Email contains the expected HTML string'); + $this->assertFalse(strpos($email['Content'], $title) !== false, 'Email contains the field name'); + $this->assertFalse(strpos($email['Content'], $value) !== false, 'Email contains the field value'); + } + +} diff --git a/tests/RecaptchaV3FieldFunctionalTest.yml b/tests/RecaptchaV3FieldFunctionalTest.yml new file mode 100644 index 0000000..694cb9f --- /dev/null +++ b/tests/RecaptchaV3FieldFunctionalTest.yml @@ -0,0 +1,50 @@ +# reCAPTCHAv3 fixture, based on UserDefinedForm.yml +SilverStripe\UserForms\Model\Recipient\EmailRecipient: + recipient-include: + EmailAddress: test.include@example.com + EmailSubject: 'Include: test form submission for reCAPTCHAv3 test' + EmailFrom: no-reply@example.com + EmailBodyHtml: 'INCLUDE_IN_EMAILS' + recipient-not-include: + EmailAddress: test.notinclude@example.com + EmailSubject: 'Not include: test form submission for reCAPTCHAv3 test' + EmailFrom: no-reply@example.com + EmailBodyHtml: 'NOT_INCLUDE_IN_EMAILS' + +SilverStripe\UserForms\Model\EditableFormField\EditableFormStep: + include-in-emails-step1: + Title: 'Include Step 1' + not-include-in-emails-step1: + Title: 'Not include Step 1' + +NSWDPC\SpamProtection\EditableRecaptchaV3Field: + include-in-emails: + Name: include_in_emails + Title: Include value in emails + IncludeInEmails: 1 + Action: functionaltest + Score: 0.7 + not-include-in-emails: + Name: not_include_in_emails + Title: Not include value in emails + IncludeInEmails: 0 + Action: functionaltest + Score: 0.7 + +SilverStripe\UserForms\Model\UserDefinedForm: + include-in-emails: + Content: '

Form test: Include in emails

' + Title: Include in emails + Fields: + - =>SilverStripe\UserForms\Model\EditableFormField\EditableFormStep.include-in-emails-step1 + - =>NSWDPC\SpamProtection\EditableRecaptchaV3Field.include-in-emails + EmailRecipients: + - =>SilverStripe\UserForms\Model\Recipient\EmailRecipient.recipient-include + not-include-in-emails: + Content: '

Form test: Do not include in emails

' + Title: Not include in emails + Fields: + - =>SilverStripe\UserForms\Model\EditableFormField\EditableFormStep.not-include-in-emails-step1 + - =>NSWDPC\SpamProtection\EditableRecaptchaV3Field.not-include-in-emails + EmailRecipients: + - =>SilverStripe\UserForms\Model\Recipient\EmailRecipient.recipient-not-include diff --git a/tests/RecaptchaV3FieldTest.php b/tests/RecaptchaV3FieldTest.php new file mode 100644 index 0000000..a32d4f5 --- /dev/null +++ b/tests/RecaptchaV3FieldTest.php @@ -0,0 +1,42 @@ +Title = "Test spam protection"; + $field->IncludeInEmails = 1; + + $submittedField = $field->getSubmittedFormField(); + $this->assertTrue( $submittedField->getIncludeValueInEmails(), "getIncludeValueInEmails should be true when IncludeInEmails=1" ); + + $field->IncludeInEmails = 0; + + $submittedField = $field->getSubmittedFormField(); + $this->assertFalse( $submittedField->getIncludeValueInEmails(), "getIncludeValueInEmails should be false when IncludeInEmails=0" ); + } + + + +} From d280e8bbf911525c60d0a95a7c5ef7928bef4d83 Mon Sep 17 00:00:00 2001 From: "James (DPC)" Date: Tue, 25 Jan 2022 10:04:08 +1100 Subject: [PATCH 2/9] Provide commit option in task, add notes on usage, normalise segment with field naming --- src/Tasks/IncludeInEmailsTask.php | 35 +++++++++++++++++++------------ 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/Tasks/IncludeInEmailsTask.php b/src/Tasks/IncludeInEmailsTask.php index 0b2afd6..744b361 100644 --- a/src/Tasks/IncludeInEmailsTask.php +++ b/src/Tasks/IncludeInEmailsTask.php @@ -34,7 +34,7 @@ class IncludeInEmailsTask extends BuildTask /** * @var string */ - private static $segment = 'Recaptchav3IncludeInEmailsTask'; + private static $segment = 'RecaptchaV3IncludeInEmailsTask'; /** * @var string @@ -43,16 +43,25 @@ public function run($request) { $before = $request->getVar('before'); $publish = $request->getVar('publish') == 1; + $commit = $request->getVar('commit') == 1; + + if(!$commit) { + DB::alteration_message("Pass commit=1 to make changes", "info"); + } + if(!$publish) { + DB::alteration_message("Pass publish=1 to publish changes", "info"); + } if(!$before) { DB::alteration_message("You must provide a date/time as the 'before' param, to update all fields before that date/time. The value is anything understood by DateTime", "error"); + return; } try { $dt = new \DateTime($before); $beforeFormatted = $dt->format('Y-m-d'); } catch(\Exception $e) { - DB::alteration_message("Could not understand the before value '{$before}'", "error");\ + DB::alteration_message("Could not understand the before value '{$before}'", "error"); return; } @@ -65,21 +74,21 @@ public function run($request) { return; } - if(!$publish) { - DB::alteration_message("Provide publish=1 to change the published field as well", "noop"); - } - foreach($fields as $field) { try { - $field->IncludeInEmails = 1; - $field->write(); - DB::alteration_message("Changed field #{$field->ID} {$field->Title}", "changed"); - if($publish) { - $field->doPublish(); - DB::alteration_message("Published field #{$field->ID} {$field->Title}", "changed"); + if($commit) { + $field->IncludeInEmails = 1; + $field->write(); + DB::alteration_message("Changed field #{$field->ID} '{$field->Title}', created:{$field->Created}", "changed"); + if($publish) { + $field->doPublish(); + DB::alteration_message("Published field #{$field->ID} '{$field->Title}', created:{$field->Created}", "changed"); + } + } else { + DB::alteration_message("Would have changed field #{$field->ID} '{$field->Title}', created:{$field->Created}", "info"); } } catch (\Exception $e) { - DB::alteration_message("Failed to change field #{$field->ID} {$field->Title}. Error:{$e->getMessage()}", "error"); + DB::alteration_message("Failed to change field #{$field->ID} '{$field->Title}', created:{$field->Created}. Error:{$e->getMessage()}", "error"); } } } From 269d4cd5aeed0fdc84dff670fad04a2ce81c55e6 Mon Sep 17 00:00:00 2001 From: "James (DPC)" Date: Tue, 25 Jan 2022 17:38:27 +1100 Subject: [PATCH 3/9] Test improvements --- ...ditableRecaptchaV3FieldFunctionalTest.php} | 31 ++++++++++--------- ...ditableRecaptchaV3FieldFunctionalTest.yml} | 0 ...t.php => EditableRecaptchaV3FieldTest.php} | 2 +- 3 files changed, 18 insertions(+), 15 deletions(-) rename tests/{RecaptchaV3FieldFunctionalTest.php => EditableRecaptchaV3FieldFunctionalTest.php} (95%) rename tests/{RecaptchaV3FieldFunctionalTest.yml => EditableRecaptchaV3FieldFunctionalTest.yml} (100%) rename tests/{RecaptchaV3FieldTest.php => EditableRecaptchaV3FieldTest.php} (94%) diff --git a/tests/RecaptchaV3FieldFunctionalTest.php b/tests/EditableRecaptchaV3FieldFunctionalTest.php similarity index 95% rename from tests/RecaptchaV3FieldFunctionalTest.php rename to tests/EditableRecaptchaV3FieldFunctionalTest.php index 568d205..c5efd67 100644 --- a/tests/RecaptchaV3FieldFunctionalTest.php +++ b/tests/EditableRecaptchaV3FieldFunctionalTest.php @@ -15,9 +15,9 @@ /** * @package userforms */ -class Recaptchav3FieldFunctionalTest extends FunctionalTest +class EditableRecaptchav3FieldFunctionalTest extends FunctionalTest { - protected static $fixture_file = 'RecaptchaV3FieldFunctionalTest.yml'; + protected static $fixture_file = 'EditableRecaptchaV3FieldFunctionalTest.yml'; protected static $use_draft_site = false; @@ -55,8 +55,14 @@ protected function setupFormFrontend($fixtureName) public function testProcessIncludeInEmails() { + // and test verifier + Injector::inst()->registerService( + new TestVerifier(), Verifier::class + ); + $field = new TestRecaptchaV3Field('include_in_emails'); - $field->setIsSuccess(true); + // emulate human verification + $field->getVerifier()->setIsHuman(true); // use the test field Injector::inst()->registerService( @@ -64,11 +70,6 @@ public function testProcessIncludeInEmails() RecaptchaV3Field::class ); - // and test verifier - Injector::inst()->registerService( - new TestVerifier(), Verifier::class - ); - $userDefinedForm = $this->setupFormFrontend('include-in-emails'); $recipients = $userDefinedForm->EmailRecipients(); @@ -128,8 +129,15 @@ public function testProcessIncludeInEmails() } public function testProcessNotIncludeInEmails() { + + // and test verifier + Injector::inst()->registerService( + new TestVerifier(), Verifier::class + ); + $field = new TestRecaptchaV3Field('not_include_in_emails'); - $field->setIsSuccess(true); + // emulate human verification + $field->getVerifier()->setIsHuman(true); // use the test field Injector::inst()->registerService( @@ -137,11 +145,6 @@ public function testProcessNotIncludeInEmails() { RecaptchaV3Field::class ); - // and test verifier - Injector::inst()->registerService( - new TestVerifier(), Verifier::class - ); - $userDefinedForm = $this->setupFormFrontend('not-include-in-emails'); $recipients = $userDefinedForm->EmailRecipients(); diff --git a/tests/RecaptchaV3FieldFunctionalTest.yml b/tests/EditableRecaptchaV3FieldFunctionalTest.yml similarity index 100% rename from tests/RecaptchaV3FieldFunctionalTest.yml rename to tests/EditableRecaptchaV3FieldFunctionalTest.yml diff --git a/tests/RecaptchaV3FieldTest.php b/tests/EditableRecaptchaV3FieldTest.php similarity index 94% rename from tests/RecaptchaV3FieldTest.php rename to tests/EditableRecaptchaV3FieldTest.php index a32d4f5..93399a7 100644 --- a/tests/RecaptchaV3FieldTest.php +++ b/tests/EditableRecaptchaV3FieldTest.php @@ -10,7 +10,7 @@ * Test the EditableRecaptchaV3Field * @author James */ -class Recaptchav3FieldTest extends SapphireTest +class EditableRecaptchav3FieldTest extends SapphireTest { protected $usesDatabase = false; From daa3f3c78ca4a821626422baac7dc7fc904b35f3 Mon Sep 17 00:00:00 2001 From: "James (DPC)" Date: Thu, 27 Jan 2022 10:32:17 +1100 Subject: [PATCH 4/9] Improve tests, incl how Verifier is applied --- ...EditableRecaptchaV3FieldFunctionalTest.php | 50 ++++++++++++------- tests/EditableRecaptchaV3FieldTest.php | 9 ++-- 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/tests/EditableRecaptchaV3FieldFunctionalTest.php b/tests/EditableRecaptchaV3FieldFunctionalTest.php index c5efd67..b4334bb 100644 --- a/tests/EditableRecaptchaV3FieldFunctionalTest.php +++ b/tests/EditableRecaptchaV3FieldFunctionalTest.php @@ -13,28 +13,32 @@ use SilverStripe\UserForms\Model\UserDefinedForm; /** - * @package userforms + * Functional tests for {@link NSWDPC\SpamProtection\EditableRecaptchaV3Field} + * @author James */ class EditableRecaptchav3FieldFunctionalTest extends FunctionalTest { + + /** + * @var string + */ protected static $fixture_file = 'EditableRecaptchaV3FieldFunctionalTest.yml'; + /** + * @var bool + */ protected static $use_draft_site = false; + /** + * @var bool + */ protected static $disable_themes = true; + /** + * @var bool + */ protected $usesDatabase = true; - protected function setUp(): void - { - parent::setUp(); - } - - protected function tearDown(): void - { - parent::tearDown(); - } - /** * Publish a form for use on the frontend * @@ -52,17 +56,21 @@ protected function setupFormFrontend($fixtureName) return $form; } + /** + * Functional test for IncludeInEmails=1 value + */ public function testProcessIncludeInEmails() { // and test verifier + $verifier = TestVerifier::create(); + $verifier->setIsHuman(true); Injector::inst()->registerService( - new TestVerifier(), Verifier::class + $verifier, Verifier::class ); - $field = new TestRecaptchaV3Field('include_in_emails'); - // emulate human verification - $field->getVerifier()->setIsHuman(true); + $field = TestRecaptchaV3Field::create('include_in_emails'); + $field->setVerifier($verifier); // use the test field Injector::inst()->registerService( @@ -128,16 +136,20 @@ public function testProcessIncludeInEmails() } + /** + * Functional test for IncludeInEmails=0 value + */ public function testProcessNotIncludeInEmails() { // and test verifier + $verifier = TestVerifier::create(); + $verifier->setIsHuman(true); Injector::inst()->registerService( - new TestVerifier(), Verifier::class + $verifier, Verifier::class ); - $field = new TestRecaptchaV3Field('not_include_in_emails'); - // emulate human verification - $field->getVerifier()->setIsHuman(true); + $field = TestRecaptchaV3Field::create('not_include_in_emails'); + $field->setVerifier($verifier); // use the test field Injector::inst()->registerService( diff --git a/tests/EditableRecaptchaV3FieldTest.php b/tests/EditableRecaptchaV3FieldTest.php index 93399a7..76380f0 100644 --- a/tests/EditableRecaptchaV3FieldTest.php +++ b/tests/EditableRecaptchaV3FieldTest.php @@ -7,18 +7,17 @@ use SilverStripe\Dev\SapphireTest; /** - * Test the EditableRecaptchaV3Field + * Tests for the {@link NSWDPC\SpamProtection\EditableRecaptchaV3Field} * @author James */ class EditableRecaptchav3FieldTest extends SapphireTest { + /** + * @var bool + */ protected $usesDatabase = false; - public function setUp() { - parent::setUp(); - } - /** * Test field value inclusion/exclusion */ From 41f6d1bf2cf23495e21d7963d399c5a691b4aefb Mon Sep 17 00:00:00 2001 From: "James (DPC)" Date: Wed, 26 Oct 2022 16:09:14 +1100 Subject: [PATCH 5/9] Fix: update missing entries in .gitattributes file --- .gitattributes | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.gitattributes b/.gitattributes index 40fe5cc..bfb0d81 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,10 +1,13 @@ /tests export-ignore /docs export-ignore /client/src export-ignore +/.editorconfig export-ignore /.gitattributes export-ignore /.gitignore export-ignore -/.php_cs.dist -/.phpcs.xml.dist -/.phpunit.xml.dist +/.php_cs.dist export-ignore +/phpcs.xml.dist export-ignore +/phpunit.xml.dist export-ignore /.waratah export-ignore +/code_of_conduct.md export-ignore +/CONTRIBUTING.md export-ignore /README.md export-ignore From 51123cab995aac42b9edd8d6c9e1b7983d60902d Mon Sep 17 00:00:00 2001 From: "James (DPC)" Date: Wed, 26 Oct 2022 22:38:10 +1100 Subject: [PATCH 6/9] Trivial: fix warning about test/class name --- tests/EditableRecaptchaV3FieldFunctionalTest.php | 2 +- tests/EditableRecaptchaV3FieldTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/EditableRecaptchaV3FieldFunctionalTest.php b/tests/EditableRecaptchaV3FieldFunctionalTest.php index b4334bb..530accf 100644 --- a/tests/EditableRecaptchaV3FieldFunctionalTest.php +++ b/tests/EditableRecaptchaV3FieldFunctionalTest.php @@ -16,7 +16,7 @@ * Functional tests for {@link NSWDPC\SpamProtection\EditableRecaptchaV3Field} * @author James */ -class EditableRecaptchav3FieldFunctionalTest extends FunctionalTest +class EditableRecaptchaV3FieldFunctionalTest extends FunctionalTest { /** diff --git a/tests/EditableRecaptchaV3FieldTest.php b/tests/EditableRecaptchaV3FieldTest.php index 76380f0..53ed774 100644 --- a/tests/EditableRecaptchaV3FieldTest.php +++ b/tests/EditableRecaptchaV3FieldTest.php @@ -10,7 +10,7 @@ * Tests for the {@link NSWDPC\SpamProtection\EditableRecaptchaV3Field} * @author James */ -class EditableRecaptchav3FieldTest extends SapphireTest +class EditableRecaptchaV3FieldTest extends SapphireTest { /** From f5a477fbf6f52c4de1dd8f251f7b5e21e4de9ebf Mon Sep 17 00:00:00 2001 From: "James (DPC)" Date: Wed, 26 Oct 2022 22:39:15 +1100 Subject: [PATCH 7/9] ENH: apply fields using CompositeField --- src/Models/EditableRecaptchaV3Field.php | 27 ++++++++++++------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/Models/EditableRecaptchaV3Field.php b/src/Models/EditableRecaptchaV3Field.php index 05b51f3..afe0c8a 100644 --- a/src/Models/EditableRecaptchaV3Field.php +++ b/src/Models/EditableRecaptchaV3Field.php @@ -2,9 +2,9 @@ namespace NSWDPC\SpamProtection; use SilverStripe\Forms\CheckBoxField; +use SilverStripe\Forms\CompositeField; use SilverStripe\Forms\TextField; use SilverStripe\Forms\DropdownField; -use SilverStripe\Forms\HeaderField; use SilverStripe\UserForms\Model\EditableFormField; use SilverStripe\Control\Controller; @@ -149,19 +149,18 @@ public function getCMSFields() $this->Action = $this->config()->get('defaults')['Action']; } - $fields->addFieldsToTab( - "Root.Main", [ - HeaderField::create( - 'reCAPTCHAv3Header', - _t( 'NSWDPC\SpamProtection.RECAPTCHA_SETTINGS', 'reCAPTCHA v3 settings') - ), - $range_field, - RecaptchaV3SpamProtector::getActionField('Action', $this->Action), - CheckboxField::create( - 'IncludeInEmails', - _t( 'NSWDPC\SpamProtection.INCLUDE_IN_EMAILS', 'Include reCAPTCHAv3 verification information in emails') - ) - ] + $fields->addFieldToTab( + "Root.Main", + CompositeField::create( + $range_field, + RecaptchaV3SpamProtector::getActionField('Action', $this->Action), + CheckboxField::create( + 'IncludeInEmails', + _t( 'NSWDPC\SpamProtection.INCLUDE_IN_EMAILS', 'Include reCAPTCHAv3 verification information in emails') + ) + )->setTitle( + _t( 'NSWDPC\SpamProtection.RECAPTCHA_SETTINGS', 'reCAPTCHA v3 settings') + ) ); return $fields; } From 49a439b538e84b6e3cdb739f4f0e1fff700b4c0e Mon Sep 17 00:00:00 2001 From: "James (DPC)" Date: Wed, 26 Oct 2022 22:40:39 +1100 Subject: [PATCH 8/9] ENH: update title of checkbox field with a plain english default --- src/Models/EditableRecaptchaV3Field.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Models/EditableRecaptchaV3Field.php b/src/Models/EditableRecaptchaV3Field.php index afe0c8a..273db95 100644 --- a/src/Models/EditableRecaptchaV3Field.php +++ b/src/Models/EditableRecaptchaV3Field.php @@ -156,7 +156,7 @@ public function getCMSFields() RecaptchaV3SpamProtector::getActionField('Action', $this->Action), CheckboxField::create( 'IncludeInEmails', - _t( 'NSWDPC\SpamProtection.INCLUDE_IN_EMAILS', 'Include reCAPTCHAv3 verification information in emails') + _t( 'NSWDPC\SpamProtection.INCLUDE_CAPTCHA_RESULT_IN_EMAILS', 'Include captcha result in recipient emails') ) )->setTitle( _t( 'NSWDPC\SpamProtection.RECAPTCHA_SETTINGS', 'reCAPTCHA v3 settings') From 7639dfb1f88dd04ea17382420bbf68b843ee6cb1 Mon Sep 17 00:00:00 2001 From: "James (DPC)" Date: Thu, 27 Oct 2022 15:02:21 +1100 Subject: [PATCH 9/9] Require minimum v0.1.3 of nswdpc/silverstripe-recaptcha-v3 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 6c12fe4..26f591a 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ } ], "require": { - "nswdpc/silverstripe-recaptcha-v3": "^0.1", + "nswdpc/silverstripe-recaptcha-v3": "^0.1.3", "silverstripe/userforms" : "^5" }, "require-dev": {