Repository: mozmeao/basket

Issue:
Receive and store service information from FxA
We currently only receive login events from "sync" service users, and we don't receive any service information with the "verified" events. Let's work with the FxA team to figure out how best to get us information about which service(s) the user is using, and then figure out where best to store it in SFMC.

Followup from #131


Discussion:
@LaurenNiolet the FxA side is done and should land in prod before long. Now we need to decide where and how to store this info. Currently the "verified" event data is going into the `Firefox_Account_ID` data extension in SFMC. The "login" event data goes to `Sync_Device_Logins` also in SFMC. Can we just add a `Service` column to both of those, or does it need to be more than that? I think if we add it it would be safe to default all of the existing entries as "sync" since those are the only events we have gotten so far if I understand correctly.
I think a "service" column on "Firefox_Account_Id" and "Sync_Device_Logins" would be great. That would give us originating service and then subsequent services as they get added. 
@LaurenNiolet do you know who can or should get that done? Is that Brynne? Apologies if I default to pining you on these things and it's not your area. Never sure who is best now that Jess is gone. 
I'm assuming that if someone uses a known device to access a new service a new entry will be generated on sync_device_logins? As I understand how it works now, if a user uses their account to access Sync on a known device a new entry would NOT be generated. 


And as far as backfill, Sync is fine. There will be some number of users on Firefox_Account_Id who did not sign up for Sync (AMO, for example). Unknown might be more safe?


None of us know what's what anymore now that Jess is gone. I can take the AI. 
> And as far as backfill, Sync is fine. There will be some number of users on Firefox_Account_Id who did not sign up for Sync (AMO, for example). Unknown might be more safe?

True. "sync" is right for entries in `Sync_Device_Logins`, which is now not really the right name for the DE any longer, but probably not worth changing. But you're right, using something like `NA` or `UNKNOWN` for existing entries in `Firefox_Account_ID` is the right call since we really don't know.

> I'm assuming that if someone uses a known device to access a new service a new entry will be generated on sync_device_logins? As I understand how it works now, if a user uses their account to access Sync on a known device a new entry would NOT be generated.

Yes. My understanding is that we'll get an event for every login, not every use. So if they login with a new profile in Firefox to anything, we'll get a message, but if they just use sync we won't. If they use their FxA to login to Send e.g., then we should get a message, but not every time they use Send.
I have added "SERVICE" as a Text(100) field to Sync_Device_Logins and Firefox_Account_Id.
Thank you! I'll get support for that added asap.

Resolving patch:
diff --git a/basket/news/tasks.py b/basket/news/tasks.py
--- a/basket/news/tasks.py
+++ b/basket/news/tasks.py
@@ -249,6 +249,7 @@ def fxa_verified(data):
     locale = data.get('locale')
     subscribe = data.get('marketingOptIn')
     metrics = data.get('metricsContext', {})
+    service = data.get('service', '')
 
     if not locale:
         statsd.incr('fxa_verified.ignored.no_locale')
@@ -262,7 +263,7 @@ def fxa_verified(data):
     if not lang:
         return
 
-    _update_fxa_info(email, lang, fxa_id, create_date)
+    _update_fxa_info(email, lang, fxa_id, service, create_date)
 
     if subscribe:
         upsert_user.delay(SUBSCRIBE, {
@@ -284,6 +285,7 @@ def fxa_login(data):
         'user_agent': data['userAgent'],
         'fxa_id': data['uid'],
         'first_device': data['deviceCount'] == 1,
+        'service': data.get('service', '')
     }
     _add_fxa_activity(new_data)
 
@@ -307,6 +309,7 @@ def _add_fxa_activity(data):
 
     apply_updates('Sync_Device_Logins', {
         'FXA_ID': data['fxa_id'],
+        'SERVICE': data['service'],
         'LOGIN_DATE': gmttime(),
         'FIRST_DEVICE': 'y' if data.get('first_device') else 'n',
         'OS': user_agent.os.family,
@@ -318,7 +321,7 @@ def _add_fxa_activity(data):
     })
 
 
-def _update_fxa_info(email, lang, fxa_id, create_date=None):
+def _update_fxa_info(email, lang, fxa_id, service, create_date=None):
     # leaving here because easier to test
     try:
         apply_updates('Firefox_Account_ID', {
@@ -326,6 +329,7 @@ def _update_fxa_info(email, lang, fxa_id, create_date=None):
             'CREATED_DATE_': gmttime(create_date),
             'FXA_ID': fxa_id,
             'FXA_LANGUAGE_ISO2': lang,
+            'SERVICE': service,
         })
     except NewsletterException as e:
         # don't report these errors to sentry until retries exhausted


Test patch:
diff --git a/basket/news/tests/test_tasks.py b/basket/news/tests/test_tasks.py
--- a/basket/news/tests/test_tasks.py
+++ b/basket/news/tests/test_tasks.py
@@ -658,6 +658,7 @@ def _base_test(self, user_agent=False, fxa_id='123', first_device=True):
             'fxa_id': fxa_id,
             'first_device': first_device,
             'user_agent': user_agent,
+            'service': 'sync',
         }
 
         with patch('basket.news.tasks.apply_updates') as apply_updates_mock:
@@ -806,7 +807,7 @@ def test_no_subscribe(self, upsert_mock, fxa_info_mock):
         }
         fxa_verified(data)
         upsert_mock.delay.assert_not_called()
-        fxa_info_mock.assert_called_with(data['email'], 'en-US', data['uid'], None)
+        fxa_info_mock.assert_called_with(data['email'], 'en-US', data['uid'], '', None)
 
     def test_with_subscribe(self, upsert_mock, fxa_info_mock):
         data = {
@@ -814,6 +815,7 @@ def test_with_subscribe(self, upsert_mock, fxa_info_mock):
             'uid': 'the-fxa-id',
             'locale': 'en-US,en',
             'marketingOptIn': True,
+            'service': 'sync',
         }
         fxa_verified(data)
         upsert_mock.delay.assert_called_with(SUBSCRIBE, {
@@ -822,7 +824,7 @@ def test_with_subscribe(self, upsert_mock, fxa_info_mock):
             'newsletters': settings.FXA_REGISTER_NEWSLETTER,
             'source_url': settings.FXA_REGISTER_SOURCE_URL,
         })
-        fxa_info_mock.assert_called_with(data['email'], 'en-US', data['uid'], None)
+        fxa_info_mock.assert_called_with(data['email'], 'en-US', data['uid'], 'sync', None)
 
     def test_with_subscribe_and_metrics(self, upsert_mock, fxa_info_mock):
         data = {
@@ -833,7 +835,8 @@ def test_with_subscribe_and_metrics(self, upsert_mock, fxa_info_mock):
             'metricsContext': {
                 'utm_campaign': 'bowling',
                 'some_other_thing': 'Donnie',
-            }
+            },
+            'service': 'monitor',
         }
         fxa_verified(data)
         upsert_mock.delay.assert_called_with(SUBSCRIBE, {
@@ -842,7 +845,7 @@ def test_with_subscribe_and_metrics(self, upsert_mock, fxa_info_mock):
             'newsletters': settings.FXA_REGISTER_NEWSLETTER,
             'source_url': settings.FXA_REGISTER_SOURCE_URL + '?utm_campaign=bowling',
         })
-        fxa_info_mock.assert_called_with(data['email'], 'en-US', data['uid'], None)
+        fxa_info_mock.assert_called_with(data['email'], 'en-US', data['uid'], 'monitor', None)
 
     def test_with_createDate(self, upsert_mock, fxa_info_mock):
         create_date_float = 1526996035.498
@@ -854,7 +857,7 @@ def test_with_createDate(self, upsert_mock, fxa_info_mock):
             'locale': 'en-US,en'
         }
         fxa_verified(data)
-        fxa_info_mock.assert_called_with(data['email'], 'en-US', data['uid'], create_date)
+        fxa_info_mock.assert_called_with(data['email'], 'en-US', data['uid'], '', create_date)
 
 
 @patch('basket.news.tasks.upsert_user')
@@ -896,6 +899,7 @@ def test_fxa_login_task_with_no_utm(self, afa_mock, upsert_mock):
             'user_agent': data['userAgent'],
             'fxa_id': data['uid'],
             'first_device': True,
+            'service': 'sync',
         })
         upsert_mock.delay.assert_not_called()
 
@@ -906,6 +910,7 @@ def test_fxa_login_task_with_utm_data(self, afa_mock, upsert_mock):
             'user_agent': data['userAgent'],
             'fxa_id': data['uid'],
             'first_device': False,
+            'service': 'sync',
         })
         upsert_mock.delay.assert_called_with(SUBSCRIBE, {
             'email': 'the.dude@example.com',
@@ -927,6 +932,7 @@ def test_fxa_login_task_with_utm_data_no_subscribe(self, afa_mock, upsert_mock):
             'user_agent': data['userAgent'],
             'fxa_id': data['uid'],
             'first_device': False,
+            'service': 'sync',
         })
         upsert_mock.delay.assert_not_called()