From 19c439a46985714a11dffdef1959842792d13641 Mon Sep 17 00:00:00 2001 From: Dimas Date: Wed, 13 Sep 2023 13:28:03 +0700 Subject: [PATCH] [Mobile] - Add fetch wetland data api --- bims/tests/test_feature_info.py | 42 +++++++++++++++++++++++ bims/utils/feature_info.py | 55 ++++++++++++++++++++++++++++++ mobile/api_views/river.py | 4 +-- mobile/api_views/wetland.py | 60 +++++++++++++++++++++++++++++++++ mobile/urls.py | 4 +++ 5 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 bims/tests/test_feature_info.py create mode 100644 bims/utils/feature_info.py create mode 100644 mobile/api_views/wetland.py diff --git a/bims/tests/test_feature_info.py b/bims/tests/test_feature_info.py new file mode 100644 index 000000000..d82bfe36c --- /dev/null +++ b/bims/tests/test_feature_info.py @@ -0,0 +1,42 @@ +from django.test import TestCase +from unittest.mock import patch + +from requests import HTTPError + +from bims.utils.feature_info import get_feature_info_from_wms + + +class TestGetFeatureInfoFromWMS(TestCase): + + @patch('requests.get') + def test_successful_request(self, mock_get): + mock_response = mock_get.return_value + mock_response.status_code = 200 + mock_response.json.return_value = {'feature': 'some_info'} + + result = get_feature_info_from_wms( + "http://your.wms.server", + "your_layer", "EPSG:4326", 40.7128, -74.0060, 800, 600) + + self.assertEqual(result, {'feature': 'some_info'}) + + @patch('requests.get') + def test_unsuccessful_request(self, mock_get): + mock_response = mock_get.return_value + mock_response.status_code = 404 + + result = get_feature_info_from_wms( + "http://your.wms.server", + "your_layer", "EPSG:4326", 40.7128, -74.0060, 800, 600) + + self.assertEqual(result, None) + + @patch('requests.get') + def test_request_exception(self, mock_get): + mock_get.side_effect = HTTPError() + + result = get_feature_info_from_wms( + "http://your.wms.server", + "your_layer", "EPSG:4326", 40.7128, -74.0060, 800, 600) + + self.assertEqual(result, None) diff --git a/bims/utils/feature_info.py b/bims/utils/feature_info.py new file mode 100644 index 000000000..4ca11be3b --- /dev/null +++ b/bims/utils/feature_info.py @@ -0,0 +1,55 @@ +from typing import Union, Dict + +import requests +from requests import HTTPError + + +def get_feature_info_from_wms( + base_wms_url: str, + layer: str, srs: str, + latitude: float, + longitude: float, width: int, height: int) -> Union[Dict, None]: + """ + Fetch feature information from a WMS layer based on given latitude and longitude. + + Parameters: + base_wms_url (str): The base URL of the WMS service. + layer (str): The name of the WMS layer to query. + srs (str): The Spatial Reference System (e.g., "EPSG:4326"). + latitude (float): The latitude of the location. + longitude (float): The longitude of the location. + width (int): The width of the map in pixels. + height (int): The height of the map in pixels. + + Returns: + Union[Dict, None]: Returns a dictionary containing the feature info if successful, or None if unsuccessful. + + Examples: + >>> get_feature_info_from_wms("http://your.wms.server", "your_layer", "EPSG:4326", 40.7128, -74.0060, 800, 600) + {...} # Feature information in dictionary form + """ + + params = { + 'request': 'GetFeatureInfo', + 'service': 'WMS', + 'srs': srs, + 'version': '1.1.1', + 'format': 'image/png', + 'layers': layer, + 'query_layers': layer, + 'info_format': 'application/json', + 'width': width, + 'height': height, + 'x': int(width / 2), + 'y': int(height / 2), + 'bbox': f"{longitude-0.1},{latitude-0.1},{longitude+0.1},{latitude+0.1}" + } + + try: + response = requests.get(base_wms_url, params=params) + if response.status_code == 200: + return response.json() + except HTTPError: + return None + + return None diff --git a/mobile/api_views/river.py b/mobile/api_views/river.py index 3eb3b16b9..b2d1eddc5 100644 --- a/mobile/api_views/river.py +++ b/mobile/api_views/river.py @@ -1,4 +1,4 @@ - +from guardian.mixins import LoginRequiredMixin from rest_framework.response import Response from rest_framework.views import APIView @@ -6,7 +6,7 @@ from sass.models import River -class FetchRiverName(APIView): +class FetchRiverName(LoginRequiredMixin, APIView): def get(self, request, *args): lat = request.GET.get('lat', '') lon = request.GET.get('lon', '') diff --git a/mobile/api_views/wetland.py b/mobile/api_views/wetland.py new file mode 100644 index 000000000..04dd3d069 --- /dev/null +++ b/mobile/api_views/wetland.py @@ -0,0 +1,60 @@ +from typing import Union, Dict + +from guardian.mixins import LoginRequiredMixin +from rest_framework.views import APIView +from rest_framework.response import Response + +from bims.utils.feature_info import get_feature_info_from_wms + + +def fetch_wetland_data(latitude: float, longitude: float) -> Union[Dict, None]: + """ + Fetch wetland data from GeoContext based on given latitude and longitude. + + Parameters: + latitude (float): The latitude of the LocationSite. + longitude (float): The longitude of the LocationSite. + + Returns: + Union[Dict, None]: Returns a dictionary containing the wetland data if the fetch is successful. + Returns None if the fetch fails. + + Examples: + >>> fetch_wetland_data(40.7128, -74.0060) + {...} # some wetland data in dictionary form + + >>> fetch_wetland_data(0, 0) + None + """ + wetland = None + wetland_layer_name = 'kartoza:nwm6_beta_v3_20230714' + base_wms_layer = 'https://maps.kartoza.com/geoserver/wms' + + wms_data = get_feature_info_from_wms( + base_wms_layer, + wetland_layer_name, + 'EPSG:4326', + latitude, + longitude, + 800, 600 + ) + + if wms_data and 'features' in wms_data and wms_data['features']: + feature_data = wms_data['features'][0] + wetland = feature_data['properties'] + + return wetland + + +class FetchWetland(LoginRequiredMixin, APIView): + + def get(self, request, *args): + lat = float(request.GET.get('lat', '0')) + lon = float(request.GET.get('lon', '0')) + + wetland = fetch_wetland_data( + lat, + lon + ) + + return Response(wetland) diff --git a/mobile/urls.py b/mobile/urls.py index 9c1311771..7087e4c57 100644 --- a/mobile/urls.py +++ b/mobile/urls.py @@ -13,6 +13,7 @@ from mobile.api_views.taxon_group import TaxonGroupList from mobile.api_views.source_reference import SourceReferenceMobileList from mobile.api_views.river import FetchRiverName +from mobile.api_views.wetland import FetchWetland urlpatterns = [ @@ -52,4 +53,7 @@ path('river/', FetchRiverName.as_view(), name='fetch-river-name'), + path('wetland/', + FetchWetland.as_view(), + name='fetch-wetland'), ]