services/celery_push_notifications.py
def celery_send_push_notification(fcm_token: str, survey_obj_ids: List[str], schedule_pks: List[int]):
    ''' Celery task that sends push notifications. Note that this list of pks may contain duplicates.'''
    # Oh.  The reason we need the patient_id is so that we can debug anything ever. lol...
    patient_id = ParticipantFCMHistory.objects.filter(token=fcm_token) \
        .values_list("participant__patient_id", flat=True).get()

    with make_error_sentry(sentry_type=SentryTypes.data_processing):
        if not check_firebase_instance():
            print("Firebase credentials are not configured.")
            return

        # use the earliest timed schedule as our reference for the sent_time parameter.  (why?)
        participant = Participant.objects.get(patient_id=patient_id)
        schedules = ScheduledEvent.objects.filter(pk__in=schedule_pks)
        reference_schedule = schedules.order_by("scheduled_time").first()
        survey_obj_ids = list(set(survey_obj_ids))  # already deduped; whatever.

        print(f"Sending push notification to {patient_id} for {survey_obj_ids}...")
        try:
            send_push_notification(participant, reference_schedule, survey_obj_ids, fcm_token)
        # error types are documented at firebase.google.com/docs/reference/fcm/rest/v1/ErrorCode
        except UnregisteredError:
            print("\nUnregisteredError\n")
            # Is an internal 404 http response, it means the token that was used has been disabled.
            # Mark the fcm history as out of date, return early.
            ParticipantFCMHistory.objects.filter(token=fcm_token).update(unregistered=timezone.now())
            return

        except QuotaExceededError as e:
            # Limits are very high, this should be impossible. Reraise because this requires
            # sysadmin attention and probably new development to allow multiple firebase
            # credentials. Read comments in settings.py if toggling.
            if BLOCK_QUOTA_EXCEEDED_ERROR:
                failed_send_handler(participant, fcm_token, str(e), schedules)
                return
            else:
                raise

        except ThirdPartyAuthError as e:
            print("\nThirdPartyAuthError\n")
            failed_send_handler(participant, fcm_token, str(e), schedules)
            # This means the credentials used were wrong for the target app instance.  This can occur
            # both with bad server credentials, and with bad device credentials.
            # We have only seen this error statement, error name is generic so there may be others.
            if str(e) != "Auth error from APNS or Web Push Service":
                raise
            return

        except SenderIdMismatchError as e:
            # TODO: need text of error message certainty of multiple similar error cases.
            # (but behavior shouldn't be broken anymore, failed_send_handler executes.)
            print("\nSenderIdMismatchError:\n")
            print(e)
            failed_send_handler(participant, fcm_token, str(e), schedules)
            return

        except ValueError as e:
            print("\nValueError\n")
            # This case occurs ever? is tested for in check_firebase_instance... weird race condition?
            # Error should be transient, and like all other cases we enqueue the next weekly surveys regardless.
            if "The default Firebase app does not exist" in str(e):
                enqueue_weekly_surveys(participant, schedules)
                return
            else:
                raise

        except Exception as e:
            failed_send_handler(participant, fcm_token, str(e), schedules)
            return

        success_send_handler(participant, fcm_token, schedules)
 Celery task that sends push notifications. Note that this list of pks may contain duplicates.
Celery task that sends push notifications. Note that this list of pks may contain duplicates.
Celery task that sends push notifications . Note that this list of pks may contain duplicates .
def celery_send_push_notification(fcm_token: str, survey_obj_ids: List[str], schedule_pks: List[int]):
    patient_id = ParticipantFCMHistory.objects.filter(token=fcm_token) \
        .values_list("participant__patient_id", flat=True).get()
    with make_error_sentry(sentry_type=SentryTypes.data_processing):
        if not check_firebase_instance():
            print("Firebase credentials are not configured.")
            return
        participant = Participant.objects.get(patient_id=patient_id)
        schedules = ScheduledEvent.objects.filter(pk__in=schedule_pks)
        reference_schedule = schedules.order_by("scheduled_time").first()
        survey_obj_ids = list(set(survey_obj_ids))  
        print(f"Sending push notification to {patient_id} for {survey_obj_ids}...")
        try:
            send_push_notification(participant, reference_schedule, survey_obj_ids, fcm_token)
        except UnregisteredError:
            print("\nUnregisteredError\n")
            ParticipantFCMHistory.objects.filter(token=fcm_token).update(unregistered=timezone.now())
            return
        except QuotaExceededError as e:
            if BLOCK_QUOTA_EXCEEDED_ERROR:
                failed_send_handler(participant, fcm_token, str(e), schedules)
                return
            else:
                raise
        except ThirdPartyAuthError as e:
            print("\nThirdPartyAuthError\n")
            failed_send_handler(participant, fcm_token, str(e), schedules)
            if str(e) != "Auth error from APNS or Web Push Service":
                raise
            return
        except SenderIdMismatchError as e:
            print("\nSenderIdMismatchError:\n")
            print(e)
            failed_send_handler(participant, fcm_token, str(e), schedules)
            return
        except ValueError as e:
            print("\nValueError\n")
            if "The default Firebase app does not exist" in str(e):
                enqueue_weekly_surveys(participant, schedules)
                return
            else:
                raise
        except Exception as e:
            failed_send_handler(participant, fcm_token, str(e), schedules)
            return
        success_send_handler(participant, fcm_token, schedules)
def celery_send_push_notification ( fcm_token : str , survey_obj_ids : List [ str ] , schedule_pks : List [ int ] ) : patient_id = ParticipantFCMHistory . objects . filter ( token = fcm_token ) . values_list ( "participant__patient_id" , flat = True ) . get ( ) with make_error_sentry ( sentry_type = SentryTypes . data_processing ) : if not check_firebase_instance ( ) : print ( "Firebase credentials are not configured." ) return participant = Participant . objects . get ( patient_id = patient_id ) schedules = ScheduledEvent . objects . filter ( pk__in = schedule_pks ) reference_schedule = schedules . order_by ( "scheduled_time" ) . first ( ) survey_obj_ids = list ( set ( survey_obj_ids ) ) print ( f"Sending push notification to {patient_id} for {survey_obj_ids}..." ) try : send_push_notification ( participant , reference_schedule , survey_obj_ids , fcm_token ) except UnregisteredError : print ( "\nUnregisteredError\n" ) ParticipantFCMHistory . objects . filter ( token = fcm_token ) . update ( unregistered = timezone . now ( ) ) return except QuotaExceededError as e : if BLOCK_QUOTA_EXCEEDED_ERROR : failed_send_handler ( participant , fcm_token , str ( e ) , schedules ) return else : raise except ThirdPartyAuthError as e : print ( "\nThirdPartyAuthError\n" ) failed_send_handler ( participant , fcm_token , str ( e ) , schedules ) if str ( e ) != "Auth error from APNS or Web Push Service" : raise return except SenderIdMismatchError as e : print ( "\nSenderIdMismatchError:\n" ) print ( e ) failed_send_handler ( participant , fcm_token , str ( e ) , schedules ) return except ValueError as e : print ( "\nValueError\n" ) if "The default Firebase app does not exist" in str ( e ) : enqueue_weekly_surveys ( participant , schedules ) return else : raise except Exception as e : failed_send_handler ( participant , fcm_token , str ( e ) , schedules ) return success_send_handler ( participant , fcm_token , schedules )
Celery task that sends push notifications.
Celery task that sends push notifications .
''' Celery task that sends push notifications. Note that this list of pks may contain duplicates.''' # Oh.  The reason we need the patient_id is so that we can debug anything ever. lol... # use the earliest timed schedule as our reference for the sent_time parameter.  (why?) # already deduped; whatever. # error types are documented at firebase.google.com/docs/reference/fcm/rest/v1/ErrorCode # Is an internal 404 http response, it means the token that was used has been disabled. # Mark the fcm history as out of date, return early. # Limits are very high, this should be impossible. Reraise because this requires # sysadmin attention and probably new development to allow multiple firebase # credentials. Read comments in settings.py if toggling. # This means the credentials used were wrong for the target app instance.  This can occur # both with bad server credentials, and with bad device credentials. # We have only seen this error statement, error name is generic so there may be others. # TODO: need text of error message certainty of multiple similar error cases. # (but behavior shouldn't be broken anymore, failed_send_handler executes.) # This case occurs ever? is tested for in check_firebase_instance... weird race condition? # Error should be transient, and like all other cases we enqueue the next weekly surveys regardless.
fcm_token
str
survey_obj_ids
List[str]
schedule_pks
List[int]