@classmethod
  @gen.coroutine
  def _FormatConversationSMS(cls, client, recipient_id, viewpoint, activity):
    """Constructs an SMS message which alerts the recipient that they have access to a new
    conversation, either due to a share_new operation, or to an add_followers operation.
    The SMS message includes a clickable link to the conversation on the web site.
    """
    # Get phone number of recipient.
    recipient_user = yield gen.Task(User.Query, client, recipient_id, None)
    if recipient_user.phone is None:
      # No phone number associated with user, so can't send SMS.
      raise gen.Return(None)

    identity_key = 'Phone:%s' % recipient_user.phone

    # Get name of sharer. Try to use only the sharer's given name if the recipient is already registered.
    sharer = yield gen.Task(User.Query, client, activity.user_id, None)
    sharer_name = AlertManager._GetNameFromUser(sharer, prefer_given_name=recipient_user.IsRegistered())

    # Create ShortURL that sets prospective user cookie and then redirects to the conversation.
    viewpoint_url = yield AlertManager._CreateViewpointURL(client,
                                                           recipient_user,
                                                           identity_key,
                                                           viewpoint,
                                                           use_short_domain=True)

    # Create list of SMS message strings, in order of decreasing length. 
    sms_list = []

    if viewpoint.title:
      # 1. Use title, with photos.
      if viewpoint.cover_photo:
        text = '%s shared photos titled "%s". See them on Viewfinder: %s'
        sms_list.append(text + (sharer_name, viewpoint.title, viewpoint_url))

      # 2. Use title, without photos.
      text = '%s shared "%s" with you. See it on Viewfinder: %s'
      sms_list.append(text % (sharer_name, viewpoint.title, viewpoint_url))

      # 3. Use title, shortest form.
      text = '%s shared "%s" on Viewfinder: %s'
      sms_list.append(text % (sharer_name, viewpoint.title, viewpoint_url))

      # 4. Use title, shortest form, with given name.
      if sharer.given_name:
        sms_list.append(text % (sharer.given_name, viewpoint.title, viewpoint_url))

    if viewpoint.cover_photo:
      # 5. Omit title, with photos.
      text = '%s shared photos on Viewfinder: %s'
      sms_list.append(text % (sharer_name, viewpoint_url))

    # 6. Omit title, without photos.
    text = '%s shared on Viewfinder: %s'
    sms_list.append(text % (sharer_name, viewpoint_url))

    # 7. Use only sharer's given name.
    if sharer.given_name:
      sms_list.append(text % (sharer.given_name, viewpoint_url))

    # For registered user, don't need to mention Viewfinder.
    if recipient_user.IsRegistered():
      if viewpoint.cover_photo:
        # 8. No mention of Viewfinder, with photos.
        text = '%s shared photos: %s'
        sms_list.append(text % (sharer_name, viewpoint_url))

      # 9. No mention of Viewfinder, without photos.
      text = '%s shared: %s'
      sms_list.append(text % (sharer_name, viewpoint_url))

    # 10. Use truncated sharer name.
    remaining = sms_util.MAX_UTF16_CHARS - len(text % ('', viewpoint_url))
    name = escape.to_unicode(sharer_name)[:remaining]
    sms_list.append(text % (name, viewpoint_url))

    # Now loop through the possible SMS message string and find the first that will fit in
    # a single SMS message.
    for text in sms_list:
      # Work around Twilio bug showing Greek chars in GSM encoding. Force Unicode by replacing
      # the last space char with a tab (the one just before the web link).
      if sms_util.ForceUnicode(text):
        parts = text.rsplit(' ', 1)
        text = '\t'.join(parts)

      if sms_util.IsOneSMSMessage(text):
        break

    assert text, text

    raise gen.Return({'number': recipient_user.phone,
                      'text': text})
dataset/ETHPy150Open viewfinderco/viewfinder/backend/op/alert_manager.py/AlertManager._FormatConversationSMS/operator `%` -> `+`