diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Core/ContentHandler.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Core/ContentHandler.inc index 99c52272..101f7856 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Core/ContentHandler.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Core/ContentHandler.inc @@ -269,17 +269,46 @@ class ContentHandler { * @return array This ContentHandler as an OpenAPI 'content' schema for this MIME type in a given Response object. */ public function to_openapi_schema(Response $response, Endpoint $endpoint): array { - # Format the data schema based on the endpoint for successful responses - if ($response instanceof Success and $endpoint->many) { + # Default to an empty schema in the event we cannot determine the schema + $data_schema = [ + 'oneOf' => [['type' => 'array', 'items' => ['type' => 'object']], ['type' => 'object']], + ]; + + # Ensure the 'id' field is included for success responses on many models without a parent + if ($response instanceof Success and $endpoint->model->many and !$endpoint->model->parent_model_class) { $data_schema = [ - 'type' => 'array', - 'items' => ['$ref' => "#/components/schemas/{$endpoint->model->get_class_shortname()}"], + 'allOf' => [ + ['type' => 'object', 'properties' => ['id' => ['type' => $endpoint->model->id_type]]], + ['$ref' => "#/components/schemas/{$endpoint->model->get_class_shortname()}"], + ], ]; - } elseif ($response instanceof Success and !$endpoint->many) { + } + # Ensure the 'parent_id' and 'id' fields are included for success responses on many models with a parent + elseif ($response instanceof Success and $endpoint->model->many and $endpoint->model->parent_model_class) { + $parent_type = $endpoint->model->get_parent_model()->id_type; + $data_schema = [ + 'allOf' => [ + [ + 'type' => 'object', + 'properties' => [ + 'parent_id' => ['type' => $parent_type], + 'id' => ['type' => $endpoint->model->id_type], + ], + ], + ['$ref' => "#/components/schemas/{$endpoint->model->get_class_shortname()}"], + ], + ]; + } + # Do not include any extra fields for non many models + elseif ($response instanceof Success and !$endpoint->model->many) { $data_schema = ['$ref' => "#/components/schemas/{$endpoint->model->get_class_shortname()}"]; - } else { + } + + # If this is a many endpoint, nest the data schema in an array + if ($response instanceof Success and $endpoint->many) { $data_schema = [ - 'oneOf' => [['type' => 'array', 'items' => ['type' => 'object']], ['type' => 'object']], + 'type' => 'array', + 'items' => $data_schema, ]; } diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/NetworkInterface.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/NetworkInterface.inc index 664fedb3..d375dd9a 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/NetworkInterface.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/NetworkInterface.inc @@ -165,7 +165,7 @@ class NetworkInterface extends Model { $this->gateway = new ForeignModelField( model_name: ['RoutingGateway', 'RoutingGatewayGroup'], model_field: 'name', - model_query: ['ipprotocol' => 'inet', 'interface' => &$this->id], + model_query: ['ipprotocol' => 'inet'], allow_null: true, conditions: ['typev4' => 'static'], help_text: 'Sets the upstream gateway this interface will use. This is only applicable for WAN-type interfaces.', @@ -313,7 +313,7 @@ class NetworkInterface extends Model { $this->gatewayv6 = new ForeignModelField( model_name: ['RoutingGateway', 'RoutingGatewayGroup'], model_field: 'name', - model_query: ['ipprotocol' => 'inet6', 'interface' => &$this->id], + model_query: ['ipprotocol' => 'inet6'], allow_null: true, conditions: ['typev6' => 'staticv6'], help_text: 'Sets the upstream IPv6 gateway this interface will use. This is only applicable for WAN-type interfaces.', diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/RoutingGatewayGroupPriority.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/RoutingGatewayGroupPriority.inc index 5bd2bc85..183c3400 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/RoutingGatewayGroupPriority.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/RoutingGatewayGroupPriority.inc @@ -22,6 +22,7 @@ class RoutingGatewayGroupPriority extends Model { $this->parent_model_class = 'RoutingGatewayGroup'; $this->config_path = 'item'; $this->subsystem = 'staticroutes'; + $this->update_strategy = 'replace'; $this->many = true; $this->many_minimum = 1; diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APICoreContentHandlerTestCase.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APICoreContentHandlerTestCase.inc index 18c5c920..38701e97 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APICoreContentHandlerTestCase.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APICoreContentHandlerTestCase.inc @@ -136,7 +136,17 @@ class APICoreContentHandlerTestCase extends TestCase { 'data' => [ 'type' => 'array', 'items' => [ - '$ref' => "#/components/schemas/{$endpoint->model->get_class_shortname()}", + 'allOf' => [ + [ + 'type' => 'object', + 'properties' => [ + 'id' => ['type' => $endpoint->model->id_type], + ], + ], + [ + '$ref' => "#/components/schemas/{$endpoint->model->get_class_shortname()}", + ], + ], ], ], ], @@ -165,7 +175,17 @@ class APICoreContentHandlerTestCase extends TestCase { [ 'type' => 'object', 'properties' => [ - 'data' => ['$ref' => "#/components/schemas/{$endpoint->model->get_class_shortname()}"], + 'data' => [ + 'allOf' => [ + [ + 'type' => 'object', + 'properties' => [ + 'id' => ['type' => $endpoint->model->id_type], + ], + ], + ['$ref' => "#/components/schemas/{$endpoint->model->get_class_shortname()}"], + ], + ], ], ], ], diff --git a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsRoutingGatewayGroupPriorityTestCase.inc b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsRoutingGatewayGroupPriorityTestCase.inc index 9be7fdab..3842b82b 100644 --- a/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsRoutingGatewayGroupPriorityTestCase.inc +++ b/pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsRoutingGatewayGroupPriorityTestCase.inc @@ -58,6 +58,13 @@ class APIModelsRoutingGatewayGroupPriorityTestCase extends TestCase { $gateway_prio->tier->value = 3; $gateway_prio->update(); + # Ensure the priority was actually updated + $this->assert_equals( + RoutingGatewayGroupPriority::query(parent_id: $gateway_group->id, id: $gateway_prio->id)->first()->tier + ->value, + 3, + ); + # Delete the gateway group priority object and ensure it was deleted $gateway_prio->delete(); $this->assert_equals(RoutingGatewayGroupPriority::read_all(parent_id: $gateway_group->id)->count(), 1);