Skip to content

Commit

Permalink
feat: added auto_add_now and auto_update_now properties to DateTimeField
Browse files Browse the repository at this point in the history
  • Loading branch information
jaredhendrickson13 committed Nov 11, 2023
1 parent b82a043 commit 334caae
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 1 deletion.
54 changes: 53 additions & 1 deletion pfSense-pkg-API/files/etc/inc/api/fields/DateTimeField.inc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require_once("api/auto_loader.inc");

use API;
use API\Core\Field;
use API\Responses\ServerError;
use API\Responses\ValidationError;
use DateTime;

Expand All @@ -15,6 +16,8 @@ use DateTime;
*/
class DateTimeField extends Field {
public string $datetime_format;
public bool $auto_add_now;
public bool $auto_update_now;

/**
* Defines the StringField object and sets its options.
Expand All @@ -32,6 +35,10 @@ class DateTimeField extends Field {
* choices are dynamic and must be populated at runtime instead of pre-determined sets of values.
* @param string $datetime_format the PHP DateTime format this value should be formatted as.
* https://www.php.net/manual/en/datetime.format.php
* @param bool $auto_add_now Automatically set the value of this field to the current DateTime during initial
* creation. This field can be manually updated when this value is set.
* @param bool $auto_update_now Automatically update the value of this field to the current DateTime whenever the
* field is first created and whenever it is updated. This field will become read-only whenever this field is set.
* @param bool $allow_empty If `true`, empty strings will be allowed by this field.
* @param bool $allow_null If `true`, null values will be allowed by this field.
* @param bool $editable Set to `false` to prevent this field's value from being changed after its initial creation.
Expand Down Expand Up @@ -77,6 +84,8 @@ class DateTimeField extends Field {
array $choices = [],
string $choices_callable = "",
string $datetime_format = "m/d/Y",
bool $auto_add_now = false,
bool $auto_update_now = false,
bool $allow_empty = false,
bool $allow_null = false,
bool $editable = true,
Expand All @@ -97,7 +106,20 @@ class DateTimeField extends Field {
string $help_text = ""
)
{
# Assign properties unique to this field
$this->datetime_format = $datetime_format;
$this->auto_add_now = $auto_add_now;
$this->auto_update_now = $auto_update_now;

# Do not allow $auto_update_now and $many at the same time. The resulting array would just be redundant values.
if ($auto_update_now and $many) {
throw new ServerError(
message: "DateTimeField cannot set `auto_update_now` and `many` at the same time",
response_id: "DATETIME_FIELD_CANNOT_AUTO_UPDATE_NOW_WITH_MANY"
);
}

# Construct the parent object for this field
parent::__construct(
type: "string",
required: $required,
Expand All @@ -124,6 +146,12 @@ class DateTimeField extends Field {
validators: $validators,
help_text: $help_text
);

# Set the fields value to now if $auto_add_now is enabled
if ($this->auto_add_now) {
$current_time = (new DateTime())->format($this->datetime_format);
$this->value = ($this->many) ? [$current_time] : $current_time;
}
}

/**
Expand All @@ -143,7 +171,31 @@ class DateTimeField extends Field {

return $datetime_obj !== false;
}


/**
* Converts the represented value into the internal pfSense value. In the event that `auto_update_now` is set, this
* method will automatically update the current value to the current datetime before converting the value to internal.
* @param mixed $representation_value The value to convert into it's internal form.
* @return array|string|null The internal value(s) suitable for writing to the pfSense configuration.
*/
public function _to_internal(mixed $representation_value): array|string|null
{
# When `auto_update_now` is set, set the value to the current datetime.
if ($this->auto_update_now) {
$this->value = (new DateTime())->format($this->datetime_format);
return parent::_to_internal($this->value);
}

# Otherwise, just return the value as usual
return parent::_to_internal($representation_value);
}

/**
* Checks if a given value's type matches this Field object's primary `type` and ensures the value matches
* the current `datetime_format`.
* @param mixed $value The value to check against assigned `type` and `datetime_format`.
* @throws ValidationError If the specified value is not a supported type or datetime format.
*/
protected function check_value_type(mixed $value)
{
# Run the parent check_value_type() method to check primitive date type (i.e. string, boolean, integer)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,41 @@ namespace API\Tests;

use API\Core\TestCase;
use API\Fields\DateTimeField;
use DateTime;

class APIFieldsDateTimeFieldTestCase extends TestCase
{
/**
* Checks that DateTimeFields cannot have `auto_update_now` and `many` set at the same time.
*/
public function test_no_many_with_auto_update_now() {
$this->assert_throws_response(
response_id: "DATETIME_FIELD_CANNOT_AUTO_UPDATE_NOW_WITH_MANY",
code: 500,
callable: function () {
new DateTimeField(auto_update_now: true, many: true);
}
);
}

/**
* Ensure the value is automatically set to the current datetime when `auto_add_now` is enabled.
*/
public function test_auto_add_now_at_creation() {
$dt = new DateTimeField(auto_add_now: true);
$current_datetime = (new DateTime())->format($dt->datetime_format);
$this->assert_equals($current_datetime, $dt->value);
}

/**
* Ensure the value is automatically updated to the current time when `auto_update_now` is set
*/
public function test_auto_update_now() {
$dt = new DateTimeField(auto_update_now: true, datetime_format: "m/d/Y H:i:s");
$current_datetime = (new DateTime())->format($dt->datetime_format);
$this->assert_equals($current_datetime, $dt->to_internal());
}

/**
* Checks that the is_valid_datetime() method correctly determines whether a datetime string matches a given format.
*/
Expand Down

0 comments on commit 334caae

Please sign in to comment.