Add generic sparse field read/write/delete API endpoints#13975
Add generic sparse field read/write/delete API endpoints#13975
Conversation
|
Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have the users @copilot on file. In order for us to review and merge your code, please contact the project maintainers to get yourself added. |
Co-authored-by: etj <717359+etj@users.noreply.github.com>
|
@copilot also add a DELETE call |
Co-authored-by: etj <717359+etj@users.noreply.github.com>
|
Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have the users @copilot on file. In order for us to review and merge your code, please contact the project maintainers to get yourself added. |
Done. Added
Also added 5 tests covering all DELETE paths. |
There was a problem hiding this comment.
Pull request overview
This PR adds generic sparse field API endpoints to enable reading, writing, and deleting arbitrary resource-related metadata beyond what's declared in the JSON schema. The implementation provides three new REST endpoints (GET, PUT, DELETE) for managing sparse fields, with appropriate permission checks and schema conflict detection.
Changes:
- Added
sparse_fieldaction toMetadataViewSetwith GET, PUT, and DELETE methods for managing external sparse field data - Implemented comprehensive test suite covering permission scenarios, schema conflicts, and CRUD operations for sparse fields
- Added security measures to prevent resource enumeration and schema field shadowing
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| geonode/metadata/api/views.py | Implements sparse_field API endpoint with GET/PUT/DELETE operations, permission checks, and schema conflict validation |
| geonode/metadata/tests/tests.py | Adds SparseFieldApiTests class with comprehensive test coverage for all sparse field operations and edge cases |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| SparseField.objects.update_or_create( | ||
| resource=resource, | ||
| name=sparsekey, | ||
| defaults={"value": value}, | ||
| ) |
There was a problem hiding this comment.
Database operations (update_or_create on line 188) are not wrapped in try-except blocks. If a database integrity error occurs (e.g., due to value length exceeding max_length or other constraint violations), it will result in an unhandled exception and a 500 Internal Server Error response instead of a more appropriate 400 Bad Request. Consider wrapping database operations in try-except blocks to catch IntegrityError, DataError, or ValidationError and return appropriate error responses.
| url_name="sparse_field", | ||
| permission_classes=[], | ||
| ) | ||
| def sparse_field(self, request, pk=None, sparsekey=None): |
There was a problem hiding this comment.
The sparsekey parameter is not validated for length or content. Since the SparseField model has a name field with max_length=64, attempting to use a key longer than 64 characters will result in a database error rather than a clear 400 Bad Request response. Consider adding validation to ensure sparsekey doesn't exceed 64 characters and only contains valid characters.
| url = self._url(self.resource.pk, "custom_key") | ||
| response = self.client.put(url, data={"value": "val"}, format="json") | ||
| self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) | ||
|
|
There was a problem hiding this comment.
No test case validates the scenario when the 'value' field is missing from the PUT request body. The current implementation would accept request.data without a 'value' key and set the field to None (due to request.data.get("value", None)). Consider adding a test to verify the behavior when the value key is absent, or alternatively, add validation to require the value field in the request.
| @patch("geonode.security.registry.PermissionsHandlerRegistry.user_has_perm", return_value=True) | |
| @patch("geonode.metadata.manager.metadata_manager.get_schema") | |
| def test_put_missing_value_field_creates_sparse_field_with_null(self, mock_get_schema, mock_perm): | |
| """ | |
| Ensure that a PUT request without a 'value' key is accepted and | |
| results in a SparseField whose value is None (current behavior). | |
| """ | |
| mock_get_schema.return_value = {"properties": {"custom_key": {}}} | |
| url = self._url(self.resource.pk, "custom_key") | |
| # Intentionally omit 'value' from the payload | |
| response = self.client.put(url, data={}, format="json") | |
| self.assertEqual(response.status_code, status.HTTP_200_OK) | |
| sf = SparseField.objects.get(resource=self.resource, name="custom_key") | |
| self.assertIsNone(sf.value) |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have the users @copilot on file. In order for us to review and merge your code, please contact the project maintainers to get yourself added. |
|
@copilot as per the UPDATE case, the DELETE should not delete keys belonging to the jsonschema. Add check and related tests. |
Co-authored-by: etj <717359+etj@users.noreply.github.com>
Done in 4cdaa01. DELETE now checks the JSON schema before deleting — returns |
|
Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have the users @copilot on file. In order for us to review and merge your code, please contact the project maintainers to get yourself added. |
|
@copilot apply "black" reformatting as configured in the project |
Co-authored-by: etj <717359+etj@users.noreply.github.com>
|
Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have the users @copilot on file. In order for us to review and merge your code, please contact the project maintainers to get yourself added. |
|
@copilot you implemented the path as `url_path=r"sparse/(?P\d+)/(?P[A-Za-z0-9_-]+)",' not as described in the original issue, why? just answer, do not perform code changes for now. |
Two differences from the issue description:
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #13975 +/- ##
===========================================
- Coverage 74.07% 52.29% -21.78%
===========================================
Files 950 950
Lines 56826 56964 +138
Branches 7719 7733 +14
===========================================
- Hits 42093 29791 -12302
- Misses 13044 25787 +12743
+ Partials 1689 1386 -303 🚀 New features to boost your workflow:
|
sparse_fieldaction with GET/PUT/DELETEblackreformatting (line-length=120 as configured in pyproject.toml)Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.