@classmethod
  @gen.coroutine
  def SendFollowerAlert(cls, client, user_id, badge, viewpoint, follower, settings, activity):
    # Only send add_followers alert to users who were added.
    if activity.name == 'add_followers':
      args_dict = json.loads(activity.json)
      if user_id not in args_dict['follower_ids']:
        return

    if follower.IsMuted():
      # User has muted this viewpoint, so don't send any alerts.
      return

    if settings.push_alerts is not None and settings.push_alerts != AccountSettings.PUSH_NONE:
      alert_text = yield AlertManager._FormatAlertText(client, viewpoint, activity)
      if alert_text is not None:
        # Only alert with sound if this is the first unread activity for the conversation.
        if follower.viewed_seq + 1 >= viewpoint.update_seq:
          sound = PushNotification.DEFAULT_SOUND
        else:
          sound = None

        viewpoint_id = viewpoint.viewpoint_id if viewpoint is not None else None
        yield AlertManager._SendDeviceAlert(client, user_id, viewpoint_id, badge, alert_text, sound=sound)

    if settings.email_alerts is not None and settings.email_alerts != AccountSettings.EMAIL_NONE:
      alert_email_args = yield AlertManager._FormatAlertEmail(client, user_id, viewpoint, activity)
      if alert_email_args is not None:
        # Possible failure of email alert should not propagate.
        try:
          yield gen.Task(EmailManager.Instance().SendEmail, description=activity.name, **alert_email_args)
        except:
          logging.exception('failed to send alert email user %d', user_id)

    if settings.sms_alerts is not None and settings.sms_alerts != AccountSettings.SMS_NONE:
      alert_sms_args = yield AlertManager._FormatAlertSMS(client, user_id, viewpoint, activity)
      if alert_sms_args is not None:
        # Don't keep sending SMS alerts if the user hasn't clicked previous links in a while.
        sms_count = settings.sms_count or 0
        if sms_count == AlertManager._SMS_ALERT_LIMIT:
          # Send SMS alert telling user that we won't send any more until they click link.
          text = alert_sms_args['text']
          alert_sms_args['text'] = 'You haven\'t viewed photos shared to you on Viewfinder. Do you want to ' \
                                   'continue receiving these links? If yes, click: %s' % text[text.rfind('https://'):]

        if sms_count <= AlertManager._SMS_ALERT_LIMIT:
          # Possible failure of SMS alert should not propagate.
          try:
            yield gen.Task(SMSManager.Instance().SendSMS, description=activity.name, **alert_sms_args)
          except:
            logging.exception('failed to send alert SMS message user %d', user_id)

        # Increment the SMS alert count.
        settings.sms_count = sms_count + 1
        yield gen.Task(settings.Update, client)
Sends an APNS and/or email alert to the given follower according to his alert settings.
dataset/ETHPy150Open viewfinderco/viewfinder/backend/op/alert_manager.py/AlertManager.SendFollowerAlert