Skip to content

Commit

Permalink
Release 1.0.0 - Support for new FB messenger features
Browse files Browse the repository at this point in the history
See HISTORY.md for changelog
  • Loading branch information
Ricky Dunlop committed Jul 4, 2016
1 parent 3cf3aa4 commit 56af27f
Show file tree
Hide file tree
Showing 16 changed files with 613 additions and 149 deletions.
21 changes: 21 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Release History

## 1.0.0

### Breaking changes

- `Elements#Image` moved to `Attachments#Image`
- `MessengerClient#send_data` renamed to `send`
- `MessengerClient#set_welcome_message removed`
- `BaseMessenger#message_echoes` and `BaseMessenger#message_reads` handlers now required
- Buttons now require a `button_type` parameter


### New features

- Support for audio, video and file attachments
- Support for sender actions
- Support for quick replies
- Support for get started button and persistent menus
- locale, timezone and gender now returned for user
- Support for phone_number button types
80 changes: 73 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ We need to extend the `BaseMessenger` class and implement methods for each of th

- `messages`
- `message_deliveries`
- `message_reads`
- `message_echoes`
- `messaging_optins`
- `messaging_postbacks`

Expand All @@ -52,6 +54,12 @@ class Messenger(BaseMessenger):
def message_deliveries(self, message):
pass
def message_reads(self, message):
pass
def message_echoes(self, message):
pass
def messaging_postbacks(self, messages):
pass
Expand Down Expand Up @@ -102,13 +110,6 @@ elem = elements.Text('Your Message')
messenger.send(elem.to_dict())
```

### Images

```
image = elements.Image(url='http://example.com/image.jpg')
messenger.send(image.to_dict())
```

### Web button

```
Expand All @@ -125,6 +126,36 @@ btn = elements.Button(title='Postback button', payload='payload')
messenger.send(btn.to_dict())
```

## Attachments

### Images

```
image = attachments.Image(url='http://example.com/image.jpg')
messenger.send(image.to_dict())
```

### Audio

```
audio = attachments.Image(url='http://example.com/audio.mp3')
messenger.send(audio.to_dict())
```

### Video

```
video = attachments.Video(url='http://example.com/video.mp4')
messenger.send(video.to_dict())
```

### Files

```
file = attachments.File(url='http://example.com/file.txt')
messenger.send(file.to_dict())
```

## Templates

Import the templates (or just the ones you need)
Expand Down Expand Up @@ -201,6 +232,41 @@ res = templates.ReceiptTemplate(
messenger.send(res.to_dict())
```

## Sender Actions

### Typing on

```
typing_on = SenderAction(sender_action='typing_on')
messenger.send(typing_on.to_dict())
```

### Typing off

```
typing_ffn = SenderAction(sender_action='typing_off')
messenger.send(typing_off.to_dict())
```

### Mark seen

```
mark_seen = SenderAction(sender_action='mark_seen')
messenger.send(mark_seen.to_dict())
```

## Quick Replies

```
quick_reply_1 = QuickReply(title='Do something', payload='Send me this payload')
quick_reply_2 = QuickReply(title='Do something else', payload='Send me this other payload')
result = QuickReplies(quick_replies=[
quick_reply_1,
quick_reply_2
])
messenger.send(result.to_dict())
```

## Development Notes

[Pandoc](http://pandoc.org/installing.html) should be installed locally to convert the README to reStructuredText format for uploading to PyPi
32 changes: 16 additions & 16 deletions fbmessenger/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import requests

__version__ = '0.1.0'
__version__ = '1.0.0'

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
Expand All @@ -19,13 +19,13 @@ def get_user_data(self, entry):
r = requests.get(
'https://graph.facebook.com/v2.6/{sender}'.format(sender=entry['sender']['id']),
params={
'fields': 'first_name,last_name,profile_pic',
'fields': 'first_name,last_name,profile_pic,locale,timezone,gender',
'access_token': self.page_access_token
}
)
return r.json()

def send_data(self, payload, entry):
def send(self, payload, entry):
r = requests.post(
'https://graph.facebook.com/v2.6/me/messages',
params={
Expand All @@ -49,22 +49,14 @@ def subscribe_app_to_page(self):
)
return r.json()

def set_welcome_message(self, payload=None):
def set_thread_setting(self, data):
actions = []
if payload:
actions = [{
'message': payload
}]
r = requests.post(
'https://graph.facebook.com/v2.6/me/thread_settings',
params={
'access_token': self.page_access_token
},
json={
'setting_type': 'call_to_actions',
'thread_state': 'new_thread',
'call_to_actions': actions
}
json=data
)
return r.json()

Expand Down Expand Up @@ -92,6 +84,14 @@ def messages(self, message):
def message_deliveries(self, message):
"""Method to handle `message_deliveries`"""

@abc.abstractmethod
def message_echoes(self, message):
"""Method to handle `message_echoes`"""

@abc.abstractmethod
def message_reads(self, message):
"""Method to handle `message_reads`"""

@abc.abstractmethod
def messaging_postbacks(self, message):
"""Method to handle `messaging_postbacks`"""
Expand All @@ -117,13 +117,13 @@ def get_user(self):
return self.client.get_user_data(self.last_message)

def send(self, payload):
return self.client.send_data(payload, self.last_message)
return self.client.send(payload, self.last_message)

def get_user_id(self):
return self.last_message['sender']['id']

def subscribe(self):
return self.client.subscribe_app_to_page()

def set_welcome_message(self, payload):
return self.client.set_welcome_message(payload)
def set_thread_setting(self, data):
return self.client.set_thread_setting(data)
42 changes: 42 additions & 0 deletions fbmessenger/attachments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
class BaseAttachment(object):
def __init__(self, attachment_type, url):
self.type = attachment_type
self.url = url

def to_dict(self):
return {
'attachment': {
'type': self.type,
'payload': {
'url': self.url
}
}
}


class Image(BaseAttachment):
def __init__(self, url):
self.attachment_type = 'image'
self.url = url
super(Image, self).__init__(self.attachment_type, self.url)


class Audio(BaseAttachment):
def __init__(self, url):
self.attachment_type = 'audio'
self.url = url
super(Audio, self).__init__(self.attachment_type, self.url)


class Video(BaseAttachment):
def __init__(self, url):
self.attachment_type = 'video'
self.url = url
super(Video, self).__init__(self.attachment_type, self.url)


class File(BaseAttachment):
def __init__(self, url):
self.attachment_type = 'file'
self.url = url
super(File, self).__init__(self.attachment_type, self.url)
40 changes: 16 additions & 24 deletions fbmessenger/elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,33 @@ def to_dict(self):
}


class Image(object):
def __init__(self, url):
self.url = url

def to_dict(self):
return {
'attachment': {
'type': 'image',
'payload': {
'url': self.url
}
}
}


class Button(object):
def __init__(self, title, url=None, payload=None):
BUTTON_TYPES = [
'web_url',
'postback',
'phone_number'
]

def __init__(self, button_type, title, url=None, payload=None):
if button_type not in self.BUTTON_TYPES:
raise ValueError('Invalid button_type provided.')
if len(title) > 20:
raise ValueError('Title cannot be longer 20 characters.')
self.type = button_type
self.title = title
self.url = url
self.payload = payload

def to_dict(self):
data = {
res = {
'type': self.type,
'title': self.title
}
if self.url:
data['type'] = 'web_url'
data['url'] = self.url
elif self.payload:
data['type'] = 'postback'
data['payload'] = self.payload

return data
res['url'] = self.url
if self.payload:
res['payload'] = self.payload
return res


class Element(object):
Expand Down
31 changes: 31 additions & 0 deletions fbmessenger/quick_replies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
class QuickReply(object):

def __init__(self, title, payload):
if len(title) > 20:
raise ValueError('Title cannot be longer 20 characters.')
if len(payload) > 1000:
raise ValueError('Payload cannot be longer 1000 characters.')

self.title = title
self.payload = payload

def to_dict(self):
return {
'content_type': 'text',
'title': self.title,
'payload': self.payload
}


class QuickReplies(object):
def __init__(self, quick_replies):
if len(quick_replies) > 10:
raise ValueError('You cannot have more than 10 quick replies.')
self.quick_replies = quick_replies

def to_dict(self):
return {
'quick_replies': [
quick_reply.to_dict() for quick_reply in self.quick_replies
]
}
16 changes: 16 additions & 0 deletions fbmessenger/sender_actions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class SenderAction(object):
SENDER_ACTIONS = [
'mark_seen',
'typing_on',
'typing_off'
]

def __init__(self, sender_action):
if sender_action not in self.SENDER_ACTIONS:
raise ValueError('Invalid sender_action provided.')
self.sender_action = sender_action

def to_dict(self):
return {
'sender_action': self.sender_action
}
Loading

0 comments on commit 56af27f

Please sign in to comment.