Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/release/RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html
* *Describe scheme changes here.*

### Code/API changes
* *Describe code/API changes here.*
* [OSDEV-1346](https://opensupplyhub.atlassian.net/browse/OSDEV-1346) - Disabled null values from the response of the OpenSearch. Disabled possible null `os_id`, `claim_id` and `source` from `PATCH api/v1/moderation-events/{moderation_id}` response.

### Architecture/Environment changes
* [OSDEV-1170](https://opensupplyhub.atlassian.net/browse/OSDEV-1170) - Added the ability to automatically create a dump from the latest shared snapshot of the anonymized database from Production environment for use in the Test and Pre-Prod environments.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ class ModerationEventUpdateSerializer(ModelSerializer):

contributor_id = IntegerField(source='contributor.id', read_only=True)
contributor_name = CharField(source='contributor.name', read_only=True)
os_id = IntegerField(source='os.id', read_only=True, allow_null=True)
claim_id = IntegerField(source='claim.id', read_only=True, allow_null=True)
source = CharField(read_only=True)
os_id = IntegerField(source='os.id', read_only=True)
claim_id = IntegerField(source='claim.id', read_only=True)

class Meta:
model = ModerationEvent
Expand Down
21 changes: 19 additions & 2 deletions src/django/api/services/opensearch/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,17 @@ def __prepare_opensearch_response(self, response):
logger.error(f"Invalid response format: {response}")
raise OpenSearchServiceException(
"Invalid response format from OpenSearch."
)
)

total_hits = response.get("hits", {}).get("total", {}).get("value", 0)
hits = response.get("hits", {}).get("hits", [])

data = []
for hit in hits:
if "_source" in hit:
data.append(self.__rename_lon_field(hit["_source"]))
source = self.__rename_lon_field(hit["_source"])
clean_source = self.__remove_null_values(source)
data.append(clean_source)
else:
logger.warning(f"Missing '_source' in hit: {hit}")

Expand All @@ -49,6 +51,21 @@ def __prepare_opensearch_response(self, response):
"data": data
}

@staticmethod
def __remove_null_values(obj):
if isinstance(obj, dict):
return {
k: OpenSearchService.__remove_null_values(v)
for k, v in obj.items()
if v is not None
}
elif isinstance(obj, list):
return [
OpenSearchService.__remove_null_values(item) for item in obj
]
else:
return obj

def search_index(self, index_name, query_body):
try:
response = self.__client.search(body=query_body, index=index_name)
Expand Down
70 changes: 70 additions & 0 deletions src/django/api/tests/test_opensearch_response_formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,76 @@ def test_prepare_opensearch_response_valid_response(self, mock_logger):
self.assertEqual(result, expected_result)
mock_logger.warning.assert_not_called()

@patch('api.services.opensearch.search.logger')
def test_prepare_opensearch_response_with_varied_null_cases(
self, mock_logger
):
response = {
"hits": {
"total": {"value": 10},
"hits": [
{"_source": {"field1": {
"os_id": "CN2024216VGFN6R",
"claim_id": 123,
"moderation_id":
"1f35a90f-70a0-4c3e-8e06-2ed8e1fc6801",
"nested_field": {
"key1": None,
"key2": "valid_value"
}
}}},
{"_source": {
"field2": {
"os_id": None,
"claim_id": None,
"moderation_id":
"1f35a90f-70a0-4c3e-8e06-2ed8e1fc6817"
}
}},
{"_source": {
"field3": {
"os_id": "TW2024336G2W87T",
"claim_id": None,
"moderation_id":
"1f35a90f-70a0-4c3e-8e06-2ed8e1fc67ee",
"empty_field": None
}
}},
{"other_field": "irrelevant"}
]
}
}
expected_result = {
"count": 10,
"data": [
{"field1": {
"os_id": "CN2024216VGFN6R",
"claim_id": 123,
"moderation_id":
"1f35a90f-70a0-4c3e-8e06-2ed8e1fc6801",
"nested_field": {
"key2": "valid_value"
}
}},
{"field2": {
"moderation_id":
"1f35a90f-70a0-4c3e-8e06-2ed8e1fc6817"
}},
{"field3": {
"os_id": "TW2024336G2W87T",
"moderation_id":
"1f35a90f-70a0-4c3e-8e06-2ed8e1fc67ee"
}}
]
}

result = self.service \
._OpenSearchService__prepare_opensearch_response(response)
self.assertEqual(result, expected_result)
mock_logger.warning.assert_called_once_with(
"Missing '_source' in hit: {'other_field': 'irrelevant'}"
)

@patch('api.services.opensearch.search.logger')
def test_prepare_opensearch_response_missing_source(self, mock_logger):
response = {
Expand Down