Repository: mozmeao/basket

Issue:
Accept a `createDate` field on the `verified` SQS message

This is to support the reconciliation between the Marketingcloud and FxA user DBs. When sending an SQS `verified` message, we want to pass in the FxA createDate so that users who have had accounts for several years do not start receiving Journeybuilder emails.

I had a quick stab at writing this myself and got lost in testing and how to parse an ISO8601 date string. I'll toss up my PR anyways, guidance or just taking over the PR would be very much appreciated.

cc @pmac 



Discussion:

Resolving patch:
diff --git a/basket/news/tasks.py b/basket/news/tasks.py
--- a/basket/news/tasks.py
+++ b/basket/news/tasks.py
@@ -1,6 +1,6 @@
 from __future__ import absolute_import, unicode_literals
 
-import datetime
+from datetime import datetime, timedelta
 import logging
 from email.utils import formatdate
 from functools import wraps
@@ -32,7 +32,6 @@
                                iso_format_unix_timestamp, parse_newsletters, parse_newsletters_csv,
                                SUBSCRIBE, UNSUBSCRIBE)
 
-
 log = logging.getLogger(__name__)
 
 BAD_MESSAGE_ID_CACHE = caches['bad_message_ids']
@@ -197,8 +196,10 @@ def wrapped(self, *args, **kwargs):
     return wrapped
 
 
-def gmttime():
-    d = datetime.datetime.now() + datetime.timedelta(minutes=10)
+def gmttime(basetime=None):
+    if basetime is None:
+        basetime = datetime.now()
+    d = basetime + timedelta(minutes=10)
     stamp = mktime(d.timetuple())
     return formatdate(timeval=stamp, localtime=False, usegmt=True)
 
@@ -241,6 +242,10 @@ def fxa_verified(data):
     # used to be handled by the fxa_register view
     email = data['email']
     fxa_id = data['uid']
+    create_date = data.get('createDate')
+    if create_date:
+        create_date = datetime.fromtimestamp(create_date)
+
     locale = data.get('locale')
     subscribe = data.get('marketingOptIn')
     metrics = data.get('metricsContext', {})
@@ -257,7 +262,7 @@ def fxa_verified(data):
     if not lang:
         return
 
-    _update_fxa_info(email, lang, fxa_id)
+    _update_fxa_info(email, lang, fxa_id, create_date)
 
     if subscribe:
         upsert_user.delay(SUBSCRIBE, {
@@ -325,13 +330,13 @@ def update_fxa_info(email, lang, fxa_id):
     _update_fxa_info(email, lang, fxa_id)
 
 
-def _update_fxa_info(email, lang, fxa_id):
+def _update_fxa_info(email, lang, fxa_id, create_date=None):
     # for use with update_fxa_info and fxa_verified
     # TODO move to fxa_verified after decomission of fxa_register view
     try:
         apply_updates('Firefox_Account_ID', {
             'EMAIL_ADDRESS_': email,
-            'CREATED_DATE_': gmttime(),
+            'CREATED_DATE_': gmttime(create_date),
             'FXA_ID': fxa_id,
             'FXA_LANGUAGE_ISO2': lang,
         })


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
@@ -6,6 +6,8 @@
 from django.test import TestCase
 from django.test.utils import override_settings
 
+from datetime import datetime
+
 import simple_salesforce as sfapi
 from mock import ANY, Mock, patch
 
@@ -19,6 +21,7 @@
     fxa_email_changed,
     fxa_login,
     fxa_verified,
+    gmttime,
     mogrify_message_id,
     NewsletterException,
     process_donation,
@@ -618,7 +621,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'])
+        fxa_info_mock.assert_called_with(data['email'], 'en-US', data['uid'], None)
 
     def test_with_subscribe(self, upsert_mock, fxa_info_mock):
         data = {
@@ -634,7 +637,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'])
+        fxa_info_mock.assert_called_with(data['email'], 'en-US', data['uid'], None)
 
     def test_with_subscribe_and_metrics(self, upsert_mock, fxa_info_mock):
         data = {
@@ -654,7 +657,19 @@ 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'])
+        fxa_info_mock.assert_called_with(data['email'], 'en-US', data['uid'], None)
+
+    def test_with_createDate(self, upsert_mock, fxa_info_mock):
+        create_date_float = 1526996035.498
+        create_date = datetime.fromtimestamp(create_date_float)
+        data = {
+            'createDate': create_date_float,
+            'email': 'thedude@example.com',
+            'uid': 'the-fxa-id',
+            'locale': 'en-US,en'
+        }
+        fxa_verified(data)
+        fxa_info_mock.assert_called_with(data['email'], 'en-US', data['uid'], create_date)
 
 
 @patch('basket.news.tasks.upsert_user')
@@ -771,3 +786,18 @@ def test_timestamps_nothin_cached(self, cache_mock, sfmc_mock):
             'FXA_ID': data['uid'],
             'NewEmailAddress': data['email'],
         })
+
+
+class GmttimeTests(TestCase):
+    @patch('basket.news.tasks.datetime')
+    def test_no_basetime_provided(self, datetime_mock):
+        # original time is 'Fri, 09 Sep 2016 13:33:55 GMT'
+        datetime_mock.now.return_value = datetime.fromtimestamp(1473428035.498)
+        formatted_time = gmttime()
+        self.assertEqual(formatted_time, 'Fri, 09 Sep 2016 13:43:55 GMT')
+
+    def test_basetime_provided(self):
+        # original time is 'Fri, 09 Sep 2016 13:33:55 GMT', updates to 13:43:55
+        basetime = datetime.fromtimestamp(1473428035.498)
+        formatted_time = gmttime(basetime)
+        self.assertEqual(formatted_time, 'Fri, 09 Sep 2016 13:43:55 GMT')