Skip to content

Commit

Permalink
Merge pull request #2 from praekeltfoundation/feature/issue-2-Impleme…
Browse files Browse the repository at this point in the history
…nt-geolocation

Implement geolocation
  • Loading branch information
Saeed Marzban committed May 15, 2018
2 parents 36a95da + 20c6c28 commit 20a999e
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 12 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ script:
- flake8 molo
- molo scaffold testapp --include molo.globalsite ^globalsite/
- cp test_settings.py testapp/testapp/settings/local.py
- cp -r molo/globalsite/geoip_db/ testapp/testapp/geoip_db
- flake8 testapp
- pip install -e testapp
- py.test --cov=molo
Expand Down
25 changes: 25 additions & 0 deletions molo/globalsite/geo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from django.contrib.gis.geoip2 import GeoIP2
from molo.globalsite.models import CountrySite


def get_country_site(request):
try:
return CountrySite.objects.get(
code=get_country_code(request)).site_url
except CountrySite.DoesNotExist:
return None


def get_client_ip(request):
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
return x_forwarded_for.split(',')[0]
else:
return request.META.get('REMOTE_ADDR')


def get_country_code(request):
try:
return GeoIP2().country_code(get_client_ip(request))
except:
return None
Binary file added molo/globalsite/geoip_db/GeoLite2-Country.mmdb
Binary file not shown.
10 changes: 9 additions & 1 deletion molo/globalsite/middleware.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.shortcuts import redirect
from django.conf import settings
from django.core.urlresolvers import reverse
from molo.globalsite import geo
from models import GlobalSiteSettings


Expand Down Expand Up @@ -31,7 +32,14 @@ def process_request(self, request):

if 'GLOBALSITE_COUNTRY_SELECTION' not in request.session and \
globalsite_settings.is_globalsite:
return redirect(reverse('molo.globalsite:country_selection'))
country_site = geo.get_country_site(request)
if country_site and globalsite_settings.geolocation:
request.session['GLOBALSITE_COUNTRY_SELECTION'] = country_site
return redirect(
request.session.get('GLOBALSITE_COUNTRY_SELECTION')
)
else:
return redirect(reverse('molo.globalsite:country_selection'))

if 'GLOBALSITE_COUNTRY_SELECTION' in request.session and \
globalsite_settings.autoredirect:
Expand Down
7 changes: 4 additions & 3 deletions molo/globalsite/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.13 on 2018-05-10 14:35
# Generated by Django 1.9.13 on 2018-05-13 18:10
from __future__ import unicode_literals

from django.db import migrations, models
Expand All @@ -21,8 +21,8 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=128, verbose_name=b'Country Name')),
('code', models.CharField(max_length=6, verbose_name=b'Country Code')),
('site_url', models.CharField(help_text=b'Link to the country site. eg http://www.zm.sitename.org/', max_length=128)),
('code', models.CharField(help_text=b'Country code is required in upper case eg. ZA', max_length=6, verbose_name=b'Country Code')),
('site_url', models.CharField(help_text=b'Link to the country site. eg. http://www.zm.sitename.org/', max_length=128)),
('flag', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.Image')),
],
options={
Expand All @@ -35,6 +35,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('is_globalsite', models.BooleanField(default=False, help_text=b'It will set this site as the global site', verbose_name=b'Activate Golobal Site')),
('autoredirect', models.BooleanField(default=False, help_text=b'When this is activated it will automatically redirect the users to the country of their choice.', verbose_name=b'Activate Auto Redirect')),
('geolocation', models.BooleanField(default=False, help_text=b'When Geolocation is activated it will automatically redirect the users to the country site of their location.', verbose_name=b'Activate Geolocation')),
('description', models.TextField(blank=True, help_text=b'This description will be displayed on the homepage of the global site', null=True)),
('site', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, to='wagtailcore.Site')),
],
Expand Down
16 changes: 13 additions & 3 deletions molo/globalsite/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ class GlobalSiteSettings(BaseSetting):
help_text='When this is activated it will automatically'
' redirect the users to the country of their choice.'
)
geolocation = models.BooleanField(
default=False,
editable=True,
verbose_name=("Activate Geolocation"),
help_text='When Geolocation is activated it will automatically'
' redirect the users to the country site of their location.'
)
description = models.TextField(
null=True, blank=True,
help_text='This description will be displayed'
Expand All @@ -28,6 +35,7 @@ class GlobalSiteSettings(BaseSetting):
[
FieldPanel('is_globalsite'),
FieldPanel('autoredirect'),
FieldPanel('geolocation'),
FieldPanel('description'),
],
heading="Global Site Settings",
Expand Down Expand Up @@ -63,11 +71,13 @@ class Meta:


class CountrySite(models.Model):
name = models.CharField(max_length=128, verbose_name=("Country Name"))
code = models.CharField(max_length=6, verbose_name=("Country Code"))
name = models.CharField(max_length=128, verbose_name="Country Name")
code = models.CharField(
max_length=6, verbose_name="Country Code",
help_text='Country code is required in upper case eg. ZA')
site_url = models.CharField(
max_length=128,
help_text='Link to the country site. eg http://www.zm.sitename.org/')
help_text='Link to the country site. eg. http://www.zm.sitename.org/')
region = models.ForeignKey(
'globalsite.Region', related_name='country_sites',
verbose_name='Country Region', blank=True, null=True,
Expand Down
43 changes: 38 additions & 5 deletions molo/globalsite/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
import pytest
from django.test import TestCase, Client
from django.http.request import HttpRequest
from django.core.urlresolvers import reverse
from wagtail.wagtailcore.models import Site
from molo.core.tests.base import MoloTestCaseMixin
from molo.globalsite.models import CountrySite, GlobalSiteSettings, Region
from molo.globalsite import geo


@pytest.mark.django_db
class TestGlobalSiteViews(TestCase, MoloTestCaseMixin):

def setUp(self):
self.request = HttpRequest()
self.mk_main()
self.mk_main2()

africa = Region.objects.create(name='Africa')
asia = Region.objects.create(name='Asia')

CountrySite.objects.create(
name='South Africa', code='za',
name='South Africa', code='ZA',
site_url='http://za.site.org', region=africa)
CountrySite.objects.create(
name='Iran', code='ir',
name='Iran', code='IR',
site_url='http://ir.site.org', region=asia)

default_site = Site.objects.get(is_default_site=True)
Expand Down Expand Up @@ -48,16 +51,16 @@ def test_country_listing(self):

def test_country_redirect(self):
response = self.client.get(
reverse('molo.globalsite:set_country', args=('za',)))
reverse('molo.globalsite:set_country', args=('ZA',)))
self.assertEquals(response.url, 'http://za.site.org')

def test_auto_redirect(self):
self.client.get(
reverse('molo.globalsite:set_country', args=('za',)))
reverse('molo.globalsite:set_country', args=('ZA',)))
response = self.client.get('/')
self.assertEquals(response.status_code, 200)
self.client.get(
reverse('molo.globalsite:set_country', args=('za',)))
reverse('molo.globalsite:set_country', args=('ZA',)))
self.setting.autoredirect = True
self.setting.save()
response = self.client.get('/')
Expand All @@ -81,3 +84,33 @@ def test_settings_globalsite_ignore_path(self):
with self.settings(GLOBAL_SITE_IGNORE_PATH=excl):
response = self.client.get(excl[0])
self.assertEquals(response.status_code, 200)

def test_country_detection_using_ip(self):
self.request.META['HTTP_X_FORWARDED_FOR'] = '41.31.255.255'
self.assertEqual(geo.get_country_code(
self.request), 'ZA')
self.assertEqual(geo.get_country_site(
self.request), 'http://za.site.org')

self.request.META['HTTP_X_FORWARDED_FOR'] = '146.185.25.250'
self.assertEqual(geo.get_country_code(
self.request), 'GB')
self.assertEqual(geo.get_country_site(
self.request), None)

self.request.META['HTTP_X_FORWARDED_FOR'] = 'http://127.0.0.1'
self.assertEqual(geo.get_country_code(
self.request), None)
self.assertEqual(geo.get_country_site(
self.request), None)

def test_geolocation_using_ip(self):
client = Client(HTTP_X_FORWARDED_FOR='41.31.255.255')
response = client.get('/')
self.assertRedirects(
response, reverse('molo.globalsite:country_selection'))

self.setting.geolocation = True
self.setting.save()
response = client.get('/')
self.assertEquals(response.url, 'http://za.site.org')
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
molo.core<6.0.0,>=5.21.2
geoip2
6 changes: 6 additions & 0 deletions test_settings.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
from .base import MIDDLEWARE_CLASSES # noqa
from os.path import abspath, dirname, join
from os import environ

MIDDLEWARE_CLASSES = MIDDLEWARE_CLASSES + [
'molo.globalsite.middleware.CountrySiteRedirectMiddleware',
]

# Global site settings
GLOBAL_SITE_URL = environ.get('GLOBAL_SITE_URL', '')
GEOIP_PATH = join(dirname(dirname(abspath(__file__))), 'geoip_db')

0 comments on commit 20a999e

Please sign in to comment.