Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pinpoint fields to notifications #2326

Merged
merged 10 commits into from
Oct 25, 2024
Merged

Conversation

sastels
Copy link
Collaborator

@sastels sastels commented Oct 15, 2024

Summary | Résumé

Add a few useful fields from the Pinpoint delivery receipts to the notification and notification_history tables.

  • add new fields to the database and python models
  • extract the fields out of the Pinpoint delivery receipts and store in the database

Related Issues | Cartes liées

Test instructions | Instructions pour tester la modification

Kinda hard to test locally :/ Figure the real test is to test in staging after we merge.

Release Instructions | Instructions pour le déploiement

None.

Reviewer checklist | Liste de vérification du réviseur

  • This PR does not break existing functionality.
  • This PR does not violate GCNotify's privacy policies.
  • This PR does not raise new security concerns. Refer to our GC Notify Risk Register document on our Google drive.
  • This PR does not significantly alter performance.
  • Additional required documentation resulting of these changes is covered (such as the README, setup instructions, a related ADR or the technical documentation).

⚠ If boxes cannot be checked off before merging the PR, they should be moved to the "Release Instructions" section with appropriate steps required to verify before release. For example, changes to celery code may require tests on staging to verify that performance has not been affected.

@sastels sastels force-pushed the add-pinpoint-fields-to-notifications branch from 3b248e6 to 5eb0117 Compare October 15, 2024 20:24
@sastels sastels marked this pull request as ready for review October 15, 2024 20:33
@@ -254,15 +254,38 @@ def pinpoint_shortcode_delivered_callback(reference=None, timestamp=1467074434,
"originationPhoneNumber": "555555",

Choose a reason for hiding this comment

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

The pinpoint_shortcode_delivered_callback function signature should be updated to include the new carrierName parameter to ensure it is passed correctly.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

nope, we don't want to ever pass it.

"messageId": reference,
"messageRequestTimestamp": timestamp,
"messageEncoding": "GSM",
"messageType": "TRANSACTIONAL",
"messageStatus": "SUCCESSFUL",
"messageStatusDescription": "Message has been accepted by phone carrier",
"totalMessageParts": 1,
"totalMessagePrice": 0.02183,
"totalCarrierFee": 0.005,
"totalMessagePrice": 0.00581,

Choose a reason for hiding this comment

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

The change in totalMessagePrice and totalCarrierFee values should be verified to ensure they are correct and consistent with the new Pinpoint delivery receipts.

"messageType": "TRANSACTIONAL",
"messageStatus": "DELIVERED",
"messageStatusDescription": "Message has been accepted by phone",
"totalMessageParts": 1,

Choose a reason for hiding this comment

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

The messageStatusDescription value 'Message has been accepted by phone' seems slightly ambiguous. Ensure this is the correct and intended description for the 'DELIVERED' status.

@@ -53,6 +53,14 @@ def process_pinpoint_results(self, response):
provider_response = receipt["messageStatusDescription"]
isFinal = receipt["isFinal"]

# some of these fields might be missing in the receipt
total_message_price = receipt.get("totalMessagePrice")

Choose a reason for hiding this comment

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

Consider adding a default value for total_message_price in case the key is missing in the receipt. This will ensure that the variable is always initialized.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

no, want it to be None if it's missing.

@@ -53,6 +53,14 @@ def process_pinpoint_results(self, response):
provider_response = receipt["messageStatusDescription"]
isFinal = receipt["isFinal"]

# some of these fields might be missing in the receipt
total_message_price = receipt.get("totalMessagePrice")
total_carrier_fee = receipt.get("totalCarrierFee")

Choose a reason for hiding this comment

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

Consider adding a default value for total_carrier_fee in case the key is missing in the receipt. This will ensure that the variable is always initialized.

sms_carrier_name = db.Column(db.String(), nullable=True)
sms_message_encoding = db.Column(db.String(), nullable=True)
sms_origination_phone_number = db.Column(db.String(), nullable=True)

CheckConstraint(

Choose a reason for hiding this comment

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

The CheckConstraint should be updated to include the new SMS columns if there are any constraints that should apply to them. Currently, it only appears to handle 'letter' type notifications.

def test_process_pinpoint_results_delivered(sample_template, notify_db, notify_db_session, callback, expected_response, mocker):
def test_process_pinpoint_results_delivered(
sample_template, notify_db, notify_db_session, callback, expected_response, origination_phone_number, mocker
):
mock_logger = mocker.patch("app.celery.process_pinpoint_receipts_tasks.current_app.logger.info")

Choose a reason for hiding this comment

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

The mock_logger variable is defined but not used in the test function. Consider removing it if it's not necessary.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It is being used later in the method...

@@ -56,6 +59,12 @@ def test_process_pinpoint_results_delivered(sample_template, notify_db, notify_d
assert mock_callback_task.called_once_with(get_notification_by_id(notification.id))

Choose a reason for hiding this comment

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

The mock_callback_task.called_once_with assertion should be mock_callback_task.assert_called_once_with to correctly use the unittest.mock library's assertion method.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

oh.... yeah fixing this led me to realize that the mock wasn't actually mocking the right thing... so good on ya, ai reviewer.

@@ -56,6 +59,12 @@ def test_process_pinpoint_results_delivered(sample_template, notify_db, notify_d
assert mock_callback_task.called_once_with(get_notification_by_id(notification.id))
assert get_notification_by_id(notification.id).status == NOTIFICATION_DELIVERED
assert get_notification_by_id(notification.id).provider_response == expected_response
assert float(get_notification_by_id(notification.id).sms_total_message_price) == 0.00581

Choose a reason for hiding this comment

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

Consider storing the result of get_notification_by_id(notification.id) in a variable to avoid multiple database calls and improve readability.


process_pinpoint_results(pinpoint_delivered_callback_missing_sms_data(reference="ref"))

assert mock_callback_task.called_once_with(get_notification_by_id(notification.id))

Choose a reason for hiding this comment

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

The method called_once_with should be assert_called_once_with to properly assert that the mock was called exactly once with the specified arguments.

Copy link
Contributor

@whabanks whabanks left a comment

Choose a reason for hiding this comment

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

LGTM!
✅ Migration works
✅ New values are passed to the front end from API
✅ Sending and whatnot still works fine locally

Copy link
Member

@jimleroyer jimleroyer left a comment

Choose a reason for hiding this comment

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

Looks good! I had a few questions.

iso_country_code = receipt.get("isoCountryCode")
carrier_name = receipt.get("carrierName")
message_encoding = receipt.get("messageEncoding")
origination_phone_number = receipt.get("originationPhoneNumber")
Copy link
Member

Choose a reason for hiding this comment

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

So many informative fields that we'll be able to get new insights from. 🥳

@@ -208,6 +219,19 @@ def _update_notification_status(notification, status, provider_response=None, bo
notification.feedback_subtype = bounce_response.get("feedback_subtype")
notification.ses_feedback_id = bounce_response.get("ses_feedback_id")
notification.ses_feedback_date = bounce_response.get("ses_feedback_date")
if sms_total_message_price:
Copy link
Member

Choose a reason for hiding this comment

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

Yeah I was wondering if we need these conditionals too, if a notification field is already None and we assign None again, that should be ok. But there might be a reason of doing it that way? 👀

op.add_column("notification_history", sa.Column("sms_iso_country_code", sa.VARCHAR(), nullable=True))
op.add_column("notification_history", sa.Column("sms_carrier_name", sa.VARCHAR(), nullable=True))
op.add_column("notification_history", sa.Column("sms_message_encoding", sa.VARCHAR(), nullable=True))
op.add_column("notification_history", sa.Column("sms_origination_phone_number", sa.VARCHAR(), nullable=True))
Copy link
Member

Choose a reason for hiding this comment

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

We should update the batch process too. I wonder if we can do it in a different PR or if that will have unintended side-effects when the archival jobs will run. Definitely something to test.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I looked at that but as far as I can tell it should pull all the fields that we've added to the history table automatically

We should definitely test it though. I'll see if I can test it locally at least. On staging I see we have a minimum 3 days for a retention period.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

tested locally

  • sent an SMS,
  • edited the database to give those fields values since we don't process the AWS receipts locally
  • also set the dates for the sms in the database to be a month ago
  • edited the schedule for the archiving task delete-sms-notifications so it would be scheduled in a couple minutes
  • reran celery locally and waited for it to run
  • checked the database - sms with correct fields now in history table, and removed from notifications table 🎉

@sastels sastels requested a review from jimleroyer October 25, 2024 14:20
@jimleroyer
Copy link
Member

Approved. Related to these items:

This PR does not significantly alter performance.

Steve will run performance tests in staging to test the changes and report back on it.

Additional required documentation resulting of these changes is covered (such as the README, setup instructions, a related ADR or the technical documentation).

We should regenerate the db doc hosted at
https://cds-snc.github.io/notification-documentation-database/

Hence these two items are not checks for this PR but we will take actions to address these.

@sastels sastels merged commit dfcc4fd into main Oct 25, 2024
5 checks passed
@sastels sastels deleted the add-pinpoint-fields-to-notifications branch October 25, 2024 14:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants