Skip to content

Commit

Permalink
Merge pull request #99 from Xpirix/geofence_feature
Browse files Browse the repository at this point in the history
Fix for geofence feature
  • Loading branch information
Xpirix authored Dec 10, 2024
2 parents f6b5cc4 + 4d2e497 commit 08c8cdc
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 24 deletions.
28 changes: 11 additions & 17 deletions qgisfeedproject/qgisfeed/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,21 +133,6 @@ def test_lang_filter(self):
self.assertTrue("Null Island QGIS Meeting" in titles)
self.assertTrue("QGIS acquired by ESRI" in titles)

def test_lat_lon_filter(self):
c = Client(HTTP_USER_AGENT='Mozilla/5.0 QGIS/32400/Fedora '
'Linux (Workstation Edition)')
response = c.get('/?lat=0&lon=0')
data = json.loads(response.content)
titles = [d['title'] for d in data]
self.assertTrue("Null Island QGIS Meeting" in titles)
self.assertFalse("QGIS Italian Meeting" in titles)

response = c.get('/?lat=44.5&lon=9.5')
data = json.loads(response.content)
titles = [d['title'] for d in data]
self.assertFalse("Null Island QGIS Meeting" in titles)
self.assertTrue("QGIS Italian Meeting" in titles)

def test_after(self):
c = Client(HTTP_USER_AGENT='Mozilla/5.0 QGIS/32400/Fedora '
'Linux (Workstation Edition)')
Expand Down Expand Up @@ -177,8 +162,6 @@ def test_after(self):
def test_invalid_parameters(self):
c = Client(HTTP_USER_AGENT='Mozilla/5.0 QGIS/32400/Fedora '
'Linux (Workstation Edition)')
response = c.get('/?lat=ZZ&lon=KK')
self.assertEqual(response.status_code, 400)
response = c.get('/?lang=KK')
self.assertEqual(response.status_code, 400)
response = c.get('/?lang=english')
Expand Down Expand Up @@ -413,6 +396,17 @@ def test_feeds_list_filtering(self):
self.assertTrue('current_order' in response.context)
self.assertTrue('form' in response.context)
self.assertTrue('count' in response.context)

def test_geofence_feature(self):
c = Client(
HTTP_USER_AGENT='Mozilla/5.0 QGIS/32400/Windows 10',
REMOTE_ADDR='180.247.213.160'
)
response = c.get('/')
self.assertEqual(response.status_code, 200)
self.assertNotContains(response, 'QGIS Italian Meeting')
self.assertNotContains(response, 'Null Island QGIS Meeting')
self.assertContains(response, 'QGIS acquired by ESRI')

class FeedsItemFormTestCase(TestCase):
"""
Expand Down
26 changes: 26 additions & 0 deletions qgisfeedproject/qgisfeed/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from django.core.mail import EmailMultiAlternatives
from django.core.mail import send_mail
from django.contrib.gis.db.models import Model
from django.http import HttpRequest
from django.contrib.gis.geoip2 import GeoIP2

logger = logging.getLogger('qgisfeed.admin')
QGISFEED_FROM_EMAIL = getattr(settings, 'QGISFEED_FROM_EMAIL', '[email protected]')
Expand Down Expand Up @@ -43,3 +45,27 @@ def get_field_max_length(ConfigurationModel: Model, field_name: str):
return config.max_characters
except ConfigurationModel.DoesNotExist:
return 500


def parse_remote_addr(request: HttpRequest) -> str:
"""Extract client IP from request."""
x_forwarded_for = request.headers.get("X-Forwarded-For", "")
if x_forwarded_for:
return x_forwarded_for.split(",")[0]
return request.META.get("REMOTE_ADDR", "")

def get_location(remote_addr: str) -> str:
"""
Return WKT location for the given remote_addr.
This should be used only for the geofence feature
and won't be saved in the database.
"""
g = GeoIP2()
if remote_addr:
try:
location = g.city(remote_addr)
location_wkt = f"POINT({location['longitude']} {location['latitude']})"
return location_wkt
except Exception as e:
return None
return None
19 changes: 12 additions & 7 deletions qgisfeedproject/qgisfeed/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from django.contrib.auth.models import User

from .forms import FeedEntryFilterForm, FeedItemForm, HomePageFilterForm
from .utils import get_field_max_length, notify_reviewers
from .utils import get_field_max_length, notify_reviewers, parse_remote_addr, get_location
from .models import QgisFeedEntry, CharacterLimitConfiguration
from .languages import LANGUAGE_KEYS
import json
Expand Down Expand Up @@ -79,13 +79,16 @@ def get_filters(self, request):
else:
raise BadRequestException("Invalid language parameter.")
filters['lang'] = lang
if request.GET.get('lat') and request.GET.get('lon'):
try:
location = 'point(%s %s)' % (request.GET.get('lon'), request.GET.get('lat'))

# Build location filter from the request's remote address
# as QGIS doesn't send the location in the request
# This is used to filter entries by location
remote_addr = parse_remote_addr(request)
if remote_addr:
location = get_location(remote_addr)
if location:
GEOSGeometry(location)
filters['location'] = location
except ValueError:
raise BadRequestException("Invalid lat/lon parameters.")

if request.GET.get('publish_from'):
try:
Expand Down Expand Up @@ -152,7 +155,9 @@ def get(self, request):
qs = qs.filter(Q(language_filter__isnull=True) | Q(language_filter=filters.get('lang')))

if filters.get('location') is not None:
qs = qs.filter(spatial_filter__contains=filters.get('location'))
qs = qs.filter(
Q(spatial_filter__contains=filters.get('location')) | Q(spatial_filter__isnull=True)
)

for record in qs.values('pk', 'publish_from', 'publish_to', 'title','image', 'content', 'url', 'sticky')[:QGISFEED_MAX_RECORDS]:
if record['publish_from']:
Expand Down

0 comments on commit 08c8cdc

Please sign in to comment.