Skip to content

Commit

Permalink
Merge pull request #21513 from JKingsnorth/core-2846-1-improve-start-…
Browse files Browse the repository at this point in the history
…end-date-validation

dev/core#2846 Towards validation of start and end dates. Forms.
  • Loading branch information
eileenmcnaughton authored Apr 27, 2022
2 parents 82ba010 + 4347c49 commit c71d455
Show file tree
Hide file tree
Showing 11 changed files with 302 additions and 41 deletions.
13 changes: 9 additions & 4 deletions CRM/Campaign/Form/Campaign.php
Original file line number Diff line number Diff line change
Expand Up @@ -249,22 +249,27 @@ public function buildQuickForm() {
];

$this->addButtons($buttons);

$this->addFormRule(['CRM_Campaign_Form_Campaign', 'formRule']);
}

/**
* add the rules (mainly global rules) for form.
* All local rules are added near the element
*
* @param $fields
* @param $files
* @param $errors
*
* @return bool|array
* @see valid_date
*/
public static function formRule($fields, $files, $errors) {
public static function formRule($fields) {
$errors = [];

// Validate start/end date inputs
$validateDates = \CRM_Utils_Date::validateStartEndDatepickerInputs('start_date', $fields['start_date'], 'end_date', $fields['end_date']);
if ($validateDates !== TRUE) {
$errors[$validateDates['key']] = $validateDates['message'];
}

return empty($errors) ? TRUE : $errors;
}

Expand Down
9 changes: 4 additions & 5 deletions CRM/Contribute/Form/ContributionPage/Settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,10 @@ public static function formRule($values, $files, $self) {
}
}

//CRM-11494
$start = CRM_Utils_Date::processDate($values['start_date']);
$end = CRM_Utils_Date::processDate($values['end_date']);
if (($end < $start) && ($end != 0)) {
$errors['end_date'] = ts('End date should be after Start date.');
// Validate start/end date inputs
$validateDates = \CRM_Utils_Date::validateStartEndDatepickerInputs('start_date', $values['start_date'], 'end_date', $values['end_date']);
if ($validateDates !== TRUE) {
$errors[$validateDates['key']] = $validateDates['message'];
}

if (!empty($self->_values['payment_processor']) && $financialType = CRM_Contribute_BAO_Contribution::validateFinancialType($values['financial_type_id'])) {
Expand Down
6 changes: 4 additions & 2 deletions CRM/Event/Form/ManageEvent/EventInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,10 @@ public function buildQuickForm() {
public static function formRule($values) {
$errors = [];

if (!empty($values['end_date']) && ($values['end_date'] < $values['start_date'])) {
$errors['end_date'] = ts('End date should be after Start date.');
// Validate start/end date inputs
$validateDates = \CRM_Utils_Date::validateStartEndDatepickerInputs('start_date', $values['start_date'], 'end_date', $values['end_date']);
if ($validateDates !== TRUE) {
$errors[$validateDates['key']] = $validateDates['message'];
}

//CRM-4286
Expand Down
8 changes: 4 additions & 4 deletions CRM/Event/Form/ManageEvent/Registration.php
Original file line number Diff line number Diff line change
Expand Up @@ -458,10 +458,10 @@ public static function formRule($values, $files, $form) {
}
}

if (isset($values['registration_start_date']) && isset($values['registration_end_date'])) {
if ($values['registration_end_date'] < $values['registration_start_date']) {
$errorMsg['registration_end_date'] = ts('Registration end date should be after Registration start date');
}
// Validate start/end date inputs
$validateDates = \CRM_Utils_Date::validateStartEndDatepickerInputs('registration_start_date', $values['registration_start_date'], 'registration_end_date', $values['registration_end_date']);
if ($validateDates !== TRUE) {
$errorMsg[$validateDates['key']] = $validateDates['message'];
}

//check that the selected profiles have either firstname+lastname or email required
Expand Down
6 changes: 6 additions & 0 deletions CRM/Price/Form/Field.php
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,12 @@ public static function formRule($fields, $files, $form) {
$errors['count'] = ts('Participant Count must be greater than zero.');
}

// Validate start/end date inputs
$validateDates = \CRM_Utils_Date::validateStartEndDatepickerInputs('active_on', $fields['active_on'], 'expire_on', $fields['expire_on']);
if ($validateDates !== TRUE) {
$errors[$validateDates['key']] = $validateDates['message'];
}

if ($form->_action & CRM_Core_Action::ADD) {
if ($fields['html_type'] != 'Text') {
$countemptyrows = 0;
Expand Down
53 changes: 53 additions & 0 deletions CRM/Utils/Date.php
Original file line number Diff line number Diff line change
Expand Up @@ -2215,4 +2215,57 @@ public static function convertDateToLocalTime($dateObject, $format = 'YmdHis') {
return $dateObject->format($format);
}

/**
* Check if the value returned by a date picker has a date section (ie: includes
* a '-' character) if it includes a time section (ie: includes a ':').
*
* @param string $value
* A date/time string input from a datepicker value.
*
* @return bool
* TRUE if valid, FALSE if there is a time without a date.
*/
public static function datePickerValueWithTimeHasDate($value) {
// If there's no : (time) or a : and a - (date) then return true
return (
strpos($value, ':') === FALSE
|| strpos($value, ':') !== FALSE && strpos($value, '-') !== FALSE
);
}

/**
* Validate start and end dates entered on a form to make sure they are
* logical. Expects the form keys to be start_date and end_date.
*
* @param string $startFormKey
* The form element key of the 'start date'
* @param string $startValue
* The value of the 'start date'
* @param string $endFormKey
* The form element key of the 'end date'
* @param string $endValue
* The value of the 'end date'
*
* @return array|bool
* TRUE if valid, an array of the erroneous form key, and error message to
* use otherwise.
*/
public static function validateStartEndDatepickerInputs($startFormKey, $startValue, $endFormKey, $endValue) {

// Check date as well as time is set
if (!empty($startValue) && !self::datePickerValueWithTimeHasDate($startValue)) {
return ['key' => $startFormKey, 'message' => ts('Please enter a date as well as a time.')];
}
if (!empty($endValue) && !self::datePickerValueWithTimeHasDate($endValue)) {
return ['key' => $endFormKey, 'message' => ts('Please enter a date as well as a time.')];
}

// Check end date is after start date
if (!empty($startValue) && !empty($endValue) && $endValue < $startValue) {
return ['key' => $endFormKey, 'message' => ts('The end date should be after the start date.')];
}

return TRUE;
}

}
76 changes: 50 additions & 26 deletions tests/phpunit/CRM/Campaign/Form/CampaignTest.php
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
<?php
/*
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC. All rights reserved. |
| |
| This work is published under the GNU AGPLv3 license with some |
| permitted exceptions and without any warranty. For full license |
| and copyright information, see https://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/

/**
* Test APIv3 civicrm_contribute_* functions
*
* @package CiviCRM_APIv3
* @subpackage API_Contribution
* @group headless
*/
class CRM_Campaign_Form_CampaignTest extends CiviUnitTestCase {

/**
* Test the submit function on the contribution page.
* Set up a correct array of form values.
*
* @return array
*/
private function getCorrectFormFields($thousandSeparator) {
return [
'goal_revenue' => '$10' . $thousandSeparator . '000',
'is_active' => 1,
'title' => 'Test Campaign',
'start_date' => date('Y-m-d'),
'includeGroups' => [],
'custom' => [],
'campaign_type_id' => 1,
];
}

/**
* Test the submit function on the campaign page.
*
* @param string $thousandSeparator
*
Expand All @@ -30,17 +31,40 @@ public function testSubmit($thousandSeparator) {
$this->createLoggedInUser();
$form = new CRM_Campaign_Form_Campaign();
$form->_action = CRM_Core_Action::ADD;
$result = CRM_Campaign_Form_Campaign::Submit([
'goal_revenue' => '$10' . $thousandSeparator . '000',
'is_active' => 1,
'title' => 'Test Campaign',
'start_date' => date('Y-m-d'),
'includeGroups' => [],
'custom' => [],
'campaign_type_id' => 1,
], $form);
$values = $this->getCorrectFormFields($thousandSeparator);
$result = CRM_Campaign_Form_Campaign::Submit($values, $form);
$campaign = $this->callAPISuccess('campaign', 'get', ['id' => $result['id']]);
$this->assertEquals('10000.00', $campaign['values'][$campaign['id']]['goal_revenue']);
}

/**
* Test end date not allowed with only 'time' part.
*
* @param string $thousandSeparator
*
* @dataProvider getThousandSeparators
*/
public function testEndDateWithoutDateNotAllowed($thousandSeparator) {
$this->setCurrencySeparators($thousandSeparator);
$values = $this->getCorrectFormFields($thousandSeparator);
$values['end_date'] = '00:01';
$validationResult = \CRM_Campaign_Form_Campaign::formRule($values);
$this->assertArrayHasKey('end_date', $validationResult);
}

/**
* Test end date must be after start date.
*
* @param string $thousandSeparator
*
* @dataProvider getThousandSeparators
*/
public function testEndDateBeforeStartDateNotAllowed($thousandSeparator) {
$this->setCurrencySeparators($thousandSeparator);
$values = $this->getCorrectFormFields($thousandSeparator);
$values['end_date'] = '1900-01-01 00:00';
$validationResult = \CRM_Campaign_Form_Campaign::formRule($values);
$this->assertArrayHasKey('end_date', $validationResult);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

class CRM_Contribute_Form_ContributionPage_SettingsTest extends CiviUnitTestCase {

/**
* Set up a correct array of form values.
*
* @return array
*/
private function getCorrectFormFields() {
return [
'title' => 'Test contribution page',
'financial_type_id' => 1,
'start_date' => date('Y-m-d'),
'end_date' => date('Y-m-d', time() + 86400),
];
}

/**
* Test correct form submission.
*/
public function testValidFormSubmission() {
$values = $this->getCorrectFormFields();
$form = new CRM_Contribute_Form_ContributionPage_Settings();
$validationResult = \CRM_Contribute_Form_ContributionPage_Settings::formRule($values, [], $form);
$this->assertEmpty($validationResult);
}

/**
* Test end date not allowed with only 'time' part.
*/
public function testEndDateWithoutDateNotAllowed() {
$values = $this->getCorrectFormFields();
$values['end_date'] = '00:01';
$form = new CRM_Contribute_Form_ContributionPage_Settings();
$validationResult = \CRM_Contribute_Form_ContributionPage_Settings::formRule($values, [], $form);
$this->assertArrayHasKey('end_date', $validationResult);
}

/**
* Test end date must be after start date.
*/
public function testEndDateBeforeStartDateNotAllowed() {
$values = $this->getCorrectFormFields();
$values['end_date'] = '1900-01-01 00:00';
$form = new CRM_Contribute_Form_ContributionPage_Settings();
$validationResult = \CRM_Contribute_Form_ContributionPage_Settings::formRule($values, [], $form);
$this->assertArrayHasKey('end_date', $validationResult);
}

}
49 changes: 49 additions & 0 deletions tests/phpunit/CRM/Event/Form/ManageEvent/EventInfoTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

class CRM_Event_Form_ManageEvent_EventInfoTest extends CiviUnitTestCase {

/**
* Set up a correct array of form values.
*
* @return array
*/
private function getCorrectFormFields() {
return [
'title' => 'A test event',
'event_type_id' => 1,
'default_role_id' => 1,
'start_date' => date('Y-m-d'),
'end_date' => date('Y-m-d', time() + 86400),
];
}

/**
* Test correct form submission.
*/
public function testValidFormSubmission() {
$values = $this->getCorrectFormFields();
$validationResult = \CRM_Event_Form_ManageEvent_EventInfo::formRule($values);
$this->assertEmpty($validationResult);
}

/**
* Test end date not allowed with only 'time' part.
*/
public function testEndDateWithoutDateNotAllowed() {
$values = $this->getCorrectFormFields();
$values['end_date'] = '00:01';
$validationResult = \CRM_Event_Form_ManageEvent_EventInfo::formRule($values);
$this->assertArrayHasKey('end_date', $validationResult);
}

/**
* Test end date must be after start date.
*/
public function testEndDateBeforeStartDateNotAllowed() {
$values = $this->getCorrectFormFields();
$values['end_date'] = '1900-01-01 00:00';
$validationResult = \CRM_Event_Form_ManageEvent_EventInfo::formRule($values);
$this->assertArrayHasKey('end_date', $validationResult);
}

}
44 changes: 44 additions & 0 deletions tests/phpunit/CRM/Event/Form/ManageEvent/RegistrationTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

class CRM_Event_Form_ManageEvent_RegistrationTest extends CiviUnitTestCase {

/**
* Set up a correct array of form values.
* @todo More fields are required for formRule to return no errors
*
* @return array
*/
private function getCorrectFormFields() {
return [
'is_online_registration' => 1,
'registration_start_date' => date('Y-m-d'),
'registration_end_date' => date('Y-m-d', time() + 86400),
'is_email_confirm' => 0,
'confirm_title' => 'Confirm your registration',
'thankyou_title' => 'Thank you for your registration',
];
}

/**
* Test end date not allowed with only 'time' part.
*/
public function testEndDateWithoutDateNotAllowed() {
$values = $this->getCorrectFormFields();
$values['registration_end_date'] = '00:01';
$form = new CRM_Event_Form_ManageEvent_Registration();
$validationResult = \CRM_Event_Form_ManageEvent_Registration::formRule($values, [], $form);
$this->assertArrayHasKey('registration_end_date', $validationResult);
}

/**
* Test end date must be after start date.
*/
public function testEndDateBeforeStartDateNotAllowed() {
$values = $this->getCorrectFormFields();
$values['registration_end_date'] = '1900-01-01 00:00';
$form = new CRM_Event_Form_ManageEvent_Registration();
$validationResult = \CRM_Event_Form_ManageEvent_Registration::formRule($values, [], $form);
$this->assertArrayHasKey('registration_end_date', $validationResult);
}

}
Loading

0 comments on commit c71d455

Please sign in to comment.