Skip to content
This repository has been archived by the owner on Jan 13, 2022. It is now read-only.

[bug 1179878] Pass user agent info from FxA to Exact Target. #148

Merged
merged 1 commit into from
Sep 11, 2015
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
19 changes: 14 additions & 5 deletions news/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from django.core.cache import get_cache
from django_statsd.clients import statsd

import user_agents
from celery.task import Task, task

from news.backends.common import NewsletterException, NewsletterNoResultsException
Expand Down Expand Up @@ -201,16 +202,24 @@ def get_external_user_data(email=None, token=None, fields=None, database=None):

@et_task
def add_fxa_activity(data):
user_agent = user_agents.parse(data['user_agent'])
device_type = 'D'
if user_agent.is_mobile:
device_type = 'M'
elif user_agent.is_tablet:
device_type = 'T'

record = {
'FXA_ID': data['fxa_id'],
'LOGIN_DATE': gmttime(),
'FIRST_DEVICE': 'y' if data['first_device'] else 'n',
'OS': user_agent.os.family,
'OS_VERSION': user_agent.os.version_string,
'BROWSER': '{0} {1}'.format(user_agent.browser.family,
user_agent.browser.version_string),
'DEVICE_NAME': user_agent.device.family,
'DEVICE_TYPE': device_type,
}
# now do magic to parse the UA string.
# good deps I've found for this:
# * https://pypi.python.org/pypi/user-agents # depends on ua-parser
# * https://pypi.python.org/pypi/ua-parser
# doesn't seem either of those support py2.6 :(

apply_updates('Sync_Device_Logins', record)

Expand Down
145 changes: 145 additions & 0 deletions news/tests/test_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from news.models import FailedTask, Subscriber
from news.newsletters import clear_sms_cache
from news.tasks import (
add_fxa_activity,
add_sms_user,
et_task,
mogrify_message_id,
Expand Down Expand Up @@ -232,3 +233,147 @@ def myfunc():
myfunc()

myfunc.retry.assert_called_with(exc=error, countdown=16 * 60)


class AddFxaActivityTests(TestCase):
def _base_test(self, user_agent=None, fxa_id='123', first_device=True):
if not user_agent:
user_agent = 'Mozilla/5.0 (Windows NT 6.1; rv:10.0) Gecko/20100101 Firefox/10.0'

data = {
'fxa_id': fxa_id,
'first_device': first_device,
'user_agent': user_agent
}
with patch('news.tasks.apply_updates') as apply_updates_mock:
add_fxa_activity(data)
record = apply_updates_mock.call_args[0][1]
return record

def test_login_date(self):
with patch('news.tasks.gmttime') as gmttime_mock:
gmttime_mock.return_value = 'this is time'
record = self._base_test()
self.assertEqual(record['LOGIN_DATE'], 'this is time')

def test_first_device(self):
record = self._base_test(first_device=True)
self.assertEqual(record['FIRST_DEVICE'], 'y')

record = self._base_test(first_device=False)
self.assertEqual(record['FIRST_DEVICE'], 'n')

def test_fxa_id(self):
record = self._base_test(fxa_id='This is id')
self.assertEqual(record['FXA_ID'], 'This is id')

def test_windows(self):
ua = 'Mozilla/5.0 (Windows NT 6.1; rv:10.0) Gecko/20100101 Firefox/10.0'
record = self._base_test(ua)
self.assertEqual(record['OS'], 'Windows 7')
self.assertEqual(record['OS_VERSION'], '') # Not sure if we expect '7' here.
self.assertEqual(record['BROWSER'], 'Firefox 10')
self.assertEqual(record['DEVICE_NAME'], 'Other')
self.assertEqual(record['DEVICE_TYPE'], 'D')

def test_mac(self):
ua = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:10.0) Gecko/20100101 Firefox/30.2'
record = self._base_test(ua)
self.assertEqual(record['OS'], 'Mac OS X')
self.assertEqual(record['OS_VERSION'], '10.6')
self.assertEqual(record['BROWSER'], 'Firefox 30.2')
self.assertEqual(record['DEVICE_NAME'], 'Other')
self.assertEqual(record['DEVICE_TYPE'], 'D')

def test_linux(self):
ua = 'Mozilla/5.0 (X11; Linux i686 on x86_64; rv:10.0) Gecko/20100101 Firefox/42.0'
record = self._base_test(ua)
self.assertEqual(record['OS'], 'Linux')
self.assertEqual(record['OS_VERSION'], '')
self.assertEqual(record['BROWSER'], 'Firefox 42')
self.assertEqual(record['DEVICE_NAME'], 'Other')
self.assertEqual(record['DEVICE_TYPE'], 'D')

def test_android_phone_below_version_41(self):
ua = 'Mozilla/5.0 (Android; Mobile; rv:40.0) Gecko/40.0 Firefox/40.0'
record = self._base_test(ua)
self.assertEqual(record['OS'], 'Android')
self.assertEqual(record['OS_VERSION'], '')
self.assertEqual(record['BROWSER'], 'Firefox Mobile 40')
self.assertEqual(record['DEVICE_NAME'], 'Generic Smartphone')
self.assertEqual(record['DEVICE_TYPE'], 'M')

def test_android_tablet_below_version_41(self):
ua = 'Mozilla/5.0 (Android; Tablet; rv:40.0) Gecko/40.0 Firefox/40.0'
record = self._base_test(ua)
self.assertEqual(record['OS'], 'Android')
self.assertEqual(record['OS_VERSION'], '')
self.assertEqual(record['BROWSER'], 'Firefox 40')
self.assertEqual(record['DEVICE_NAME'], 'Generic Tablet')
self.assertEqual(record['DEVICE_TYPE'], 'T')

def test_android_phone_from_version_41(self):
ua = 'Mozilla/5.0 (Android 4.4; Mobile; rv:41.0) Gecko/41.0 Firefox/41.0'
record = self._base_test(ua)
self.assertEqual(record['OS'], 'Android')
self.assertEqual(record['OS_VERSION'], '4.4')
self.assertEqual(record['BROWSER'], 'Firefox Mobile 41')
self.assertEqual(record['DEVICE_NAME'], 'Generic Smartphone')
self.assertEqual(record['DEVICE_TYPE'], 'M')

# TODO This reports Android 5 instead of Firefox 40
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't manage to get this working. ua_parse lib seems to get this wrong for both chrome and firefox. Filed bug ua-parser/uap-core#77

#
# def test_android_tablet_from_version_41(self):
# ua = 'Mozilla/5.0 (Android 5.0; Tablet; rv:41.0) Gecko/41.0 Firefox/41.0'
# record = self._base_test(ua)
# self.assertEqual(record['OS'], 'Android')
# self.assertEqual(record['OS_VERSION'], '5')
# self.assertEqual(record['BROWSER'], 'Firefox 40')
# self.assertEqual(record['DEVICE_NAME'], 'Generic Tablet')
# self.assertEqual(record['DEVICE_TYPE'], 'T')

def test_firefox_os_phone(self):
ua = 'Mozilla/5.0 (Mobile; rv:26.0) Gecko/26.0 Firefox/26.0'
record = self._base_test(ua)
self.assertEqual(record['OS'], 'Firefox OS')
self.assertEqual(record['OS_VERSION'], '1.2')
self.assertEqual(record['BROWSER'], 'Firefox Mobile 26')
self.assertEqual(record['DEVICE_NAME'], 'Generic Smartphone')
self.assertEqual(record['DEVICE_TYPE'], 'M')

def test_firefox_os_tablet(self):
ua = 'Mozilla/5.0 (Tablet; rv:26.0) Gecko/26.0 Firefox/26.0'
record = self._base_test(ua)

self.assertEqual(record['OS'], 'Firefox OS')
self.assertEqual(record['OS_VERSION'], '1.2')
self.assertEqual(record['BROWSER'], 'Firefox 26')
self.assertEqual(record['DEVICE_NAME'], 'Generic Tablet')
self.assertEqual(record['DEVICE_TYPE'], 'T')

def test_firefox_os_device_specific(self):
ua = 'Mozilla/5.0 (Mobile; ZTEOPEN; rv:18.1) Gecko/18.1 Firefox/18.1'
record = self._base_test(ua)
self.assertEqual(record['OS'], 'Firefox OS')
self.assertEqual(record['OS_VERSION'], '1.1')
self.assertEqual(record['BROWSER'], 'Firefox Mobile 18.1')
self.assertEqual(record['DEVICE_NAME'], 'ZTE OPEN')
self.assertEqual(record['DEVICE_TYPE'], 'M')

def test_firefox_ios_iphone(self):
ua = 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) FxiOS/1.0 Mobile/12F69 Safari/600.1.4'
record = self._base_test(ua)
self.assertEqual(record['OS'], 'iOS')
self.assertEqual(record['OS_VERSION'], '8.3')
self.assertEqual(record['BROWSER'], 'Firefox iOS 1')
self.assertEqual(record['DEVICE_NAME'], 'iPhone')
self.assertEqual(record['DEVICE_TYPE'], 'M')

def test_firefox_ios_tablet(self):
ua = 'Mozilla/5.0 (iPad; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) FxiOS/1.0 Mobile/12F69 Safari/600.1.4'
record = self._base_test(ua)
self.assertEqual(record['OS'], 'iOS')
self.assertEqual(record['OS_VERSION'], '8.3')
self.assertEqual(record['BROWSER'], 'Firefox iOS 1')
self.assertEqual(record['DEVICE_NAME'], 'iPad')
self.assertEqual(record['DEVICE_TYPE'], 'T')
2 changes: 1 addition & 1 deletion vendor
Submodule vendor updated 38 files
+36 −0 lib/python/PyYAML-3.11-py2.7.egg-info/PKG-INFO
+27 −0 lib/python/PyYAML-3.11-py2.7.egg-info/SOURCES.txt
+1 −0 lib/python/PyYAML-3.11-py2.7.egg-info/dependency_links.txt
+39 −0 lib/python/PyYAML-3.11-py2.7.egg-info/installed-files.txt
+2 −0 lib/python/PyYAML-3.11-py2.7.egg-info/top_level.txt
+1 −0 lib/python/ua_parser/__init__.py
+1 −0 lib/python/ua_parser/regexes.json
+4,744 −0 lib/python/ua_parser/regexes.yaml
+533 −0 lib/python/ua_parser/user_agent_parser.py
+245 −0 lib/python/ua_parser/user_agent_parser_test.py
+201 −0 lib/python/user_agents-1.0.1-py2.7.egg-info/PKG-INFO
+13 −0 lib/python/user_agents-1.0.1-py2.7.egg-info/SOURCES.txt
+1 −0 lib/python/user_agents-1.0.1-py2.7.egg-info/dependency_links.txt
+15 −0 lib/python/user_agents-1.0.1-py2.7.egg-info/installed-files.txt
+1 −0 lib/python/user_agents-1.0.1-py2.7.egg-info/not-zip-safe
+1 −0 lib/python/user_agents-1.0.1-py2.7.egg-info/requires.txt
+1 −0 lib/python/user_agents-1.0.1-py2.7.egg-info/top_level.txt
+3 −0 lib/python/user_agents/__init__.py
+10 −0 lib/python/user_agents/compat.py
+230 −0 lib/python/user_agents/parsers.py
+241 −0 lib/python/user_agents/tests.py
+315 −0 lib/python/yaml/__init__.py
+139 −0 lib/python/yaml/composer.py
+675 −0 lib/python/yaml/constructor.py
+85 −0 lib/python/yaml/cyaml.py
+62 −0 lib/python/yaml/dumper.py
+1,140 −0 lib/python/yaml/emitter.py
+75 −0 lib/python/yaml/error.py
+86 −0 lib/python/yaml/events.py
+40 −0 lib/python/yaml/loader.py
+49 −0 lib/python/yaml/nodes.py
+589 −0 lib/python/yaml/parser.py
+190 −0 lib/python/yaml/reader.py
+484 −0 lib/python/yaml/representer.py
+224 −0 lib/python/yaml/resolver.py
+1,457 −0 lib/python/yaml/scanner.py
+111 −0 lib/python/yaml/serializer.py
+104 −0 lib/python/yaml/tokens.py