shotvibe / shotvibe-web

ShotVibe REST API webservice
1 stars 0 forks source link

Extensions to Phone Invite system #11

Closed benny-shotvibe closed 11 years ago

benny-shotvibe commented 11 years ago

We need to add a new POST API endpoint called something like query_phone_numbers

It should accept a POST body with content:

Example:

{
  "default_country": "US",
  "phone_numbers": [
    {
      "phone_number": "2127182002",
      "contact_nickname": "John Smith",
    },
    {
      "phone_number": "2127182003",
      "contact_nickname": "Amanda",
    }
  ]
}

The API should return a body with content:

Example response for the above input:

{
  "phone_number_details": [
    {
      "phone_type": "mobile",
      "user_id": 52663,
      "avatar_url": "https://www.example.com/john_smith.jpg"
    },
    {
      "phone_type": "mobile",
      "user_id": null,
      "avatar_url": "https://www.example.com/default_42.jpg"
    }
  ]
}

Note: if mobile_phone is landline or invalid, then the fields user_id and avatar_url should simply be omitted, since only mobile phones are relevant in our app.

benny-shotvibe commented 11 years ago

I think we need 2 new models (probably should go in phone_auth.models):

class AnonymousPhoneNumber(models.Model):
    phone_number = models.CharField(max_length=32, unique=True, db_index=true)
    date_added = models.DateTimeField()
    default_avatar = models.???
    mobile_phone = models.BooleanField()
    mobile_phone_queried = models.DateTimeField()

class PhoneContact(models.Model):
    anonymous_phone_number = models.ForeignKey(AnonymousPhoneNumber)
    user = models.ForeignKey(settings.AUTH_USER_MODEL)
    date_added = models.DateTimeField()
    contact_nickname = models.TextField()
benny-shotvibe commented 11 years ago

We need to finalize how we are going to handle avatars

benny-shotvibe commented 11 years ago

The pseudo-code for the query_phone_numbers view should be something like this:

def query_phone_numbers(user, default_country, phone_numbers):
    return [process_phone_number(user, default_country, p.phone_number, p.contact_nickname) for p in phone_numbers]

def process_phone_number(user, default_country, phone_number_str, contact_nickname):
    phone_number = phonenumbers.parse(default_country, phone_number_str)
    if not phone_number.is_valid:
        return { 'phone_type': 'invalid' }
    if user_exists(phone_number):
        return {
            'phone_type': 'mobile',
            'user_id': get_user(phone_number).id,
            'avatar_url': get_user(phone_number).avatar_url
            }
    anonymous_phone_number = AnonymousPhoneNumber.get(phone_number=phone_number)
    if not anonymous_phone_number:
        is_mobile = query_if_mobile(phone_number)
        random_avatar = choose_random_avatar()
        anonymous_phone_number = AnonymousPhoneNumber.create(
            phone_number = phone_number,
            date_added = now,
            default_avatar = random_avatar,
            mobile_phone = is_mobile,
            mobile_phone_queried = now)
    PhoneContact.create_or_update(
        anonymous_phone_number = anonymous_phone_number,
        user = user,
        date_added = now,
        contact_nickname = contact_nickname)
    return {
        'phone_type': is_mobile,
        'user_id': None,
        'avatar_url': random_avatar
        }
benny-shotvibe commented 11 years ago

Please take a look at http://www.searchbug.com/api/identify-phone-number.aspx

This is the API we will use to identify if a phone number is mobile or landline

benny-shotvibe commented 11 years ago

We need to check with the above searchbug API how quickly it returns results. If it returns results immediately then we don't need the above querying state

benny-shotvibe commented 11 years ago

Update: The query_phone_numbers method needs to add additional data to the response:

I think the best way to accomplish this is to give the objects returned in the array phone_number_details an additional field: the normalized E164 formatted phone number. This way the client can simply look for duplicates and remove them.

prudnikov commented 11 years ago

Can't we just ignore duplicates on server and simple return unique numbers?

prudnikov commented 11 years ago

Don't you think we should add something identifying this object in response?

{
      "phone_type": "mobile",
      "user_id": 52663,
      "avatar_url": "https://www.example.com/john_smith.jpg"
}

or you just map array of contacts that client send to the server with array of objects in response? I'm not sure if ordering in JSON array is guaranteed to be persisted when parsing...

prudnikov commented 11 years ago

AnonymousPhoneNumber.default_avatar = models.??? — do you want this to be assigned once and used always with this number?

benny-shotvibe commented 11 years ago

AnonymousPhoneNumber.default_avatar: Yes, this should be assigned once, and be always remain the same forever. (The type of this field should be the same as the avatar field of User)

Additionally: When a new user is created, before choosing a random avatar for the new user, the server should check if the user's PhoneNumber already exists in the AnonymousPhoneNumber, and if so, the new user's avatar should be the same value that exists their, instead of being random.

The code for choosing a random avatar should probably be refactored into a function that can be shared in both parts of the code (it is still used as a fallback for choosing a random avatar for a new user in the case that the new user's phone number is not in AnonymousPhoneNumber)

benny-shotvibe commented 11 years ago

regarding unique numbers: order of arrays in JSON is guaranteed. This makes everything a lot simpler, since we don't have to invent any unique identifiers for each object. the client simply knows to match each object in the response array with each number that it sent. this means that the server cannot filter the response for duplicates, otherwise the arrays won't match up.

So I think the easiest way for the client to detect the duplicates is to simply have the server also returned the normalized E164 phone number string.

This architecture will fit very conveniently with the code structure of the client apps