djmessenger package

Submodules

djmessenger.admin module

djmessenger.apps module

class djmessenger.apps.DjmessengerConfig(app_name, app_module)

Bases: django.apps.config.AppConfig

name = 'djmessenger'

djmessenger.exceptions module

exception djmessenger.exceptions.DJMException

Bases: Exception

Base Exception for DJM

exception djmessenger.exceptions.DJMInvalidConfigException

Bases: djmessenger.exceptions.DJMException

This exception will be raised if user tried to do something that breaks the assumption made by Facebbok. For example, threading setting greeting text can have only one, if the user tried to add more, raise this exception

exception djmessenger.exceptions.DJMInvalidValueException

Bases: djmessenger.exceptions.DJMException

djmessenger.facebook_locales module

An enum to represent locales that Facebook supports

class djmessenger.facebook_locales.FacebookLocale

Bases: enum.Enum

djmessenger.filtering module

Filtering Module

Filtering module defines a BaseFilter as the most basic abstract class and all its subclasses provide some specific logic to filter a given djmessenger.receiving.Messaging object

class djmessenger.filtering.AuthenticationFilter

Bases: djmessenger.filtering.BaseFilter

should_pass(messaging)
class djmessenger.filtering.BaseFilter

Bases: djmessenger.utils.serializable.Serializable

BaseFilter is an ABC for filters, it defines an abstract method which takes a Messaging object and returns a bool to indicate whether this Messaging should be further processed

should_pass(messaging)

Takes a djmessenger.receiving.Messaging object and determines whether this object should pass this filter and continue

Parameters:messaging (djmessenger.receiving.Messaging) – A Messaging instance to filter against
Returns:True if the given messaging passed this filter and should continue with the next operation; False otherwise
Return type:bool
class djmessenger.filtering.EmailFilter

Bases: djmessenger.filtering.BaseFilter

Filter that the text sent by user is a valid email address

should_pass(messaging)
class djmessenger.filtering.LocationFilter

Bases: djmessenger.filtering.BaseFilter

Pass if messaging is a Location

should_pass(messaging)
class djmessenger.filtering.MultimediaFilter

Bases: djmessenger.filtering.BaseFilter

Pass if messaging is multimedia

should_pass(messaging)
class djmessenger.filtering.PostbackFilter

Bases: djmessenger.filtering.BaseFilter

Pass if messaging is a POSTBACK

should_pass(messaging)
class djmessenger.filtering.SimpleTextRegexFilter(regex=None)

Bases: djmessenger.filtering.BaseFilter

Pass if messaging has a text that matches the regex

An example in djmessenger.utils.default_routing_policy

{
    "name": "djmessenger.filtering.SimpleTextRegexFilter",
    "args": {
        "regex": "^你好$"
    }
}
should_pass(messaging)
class djmessenger.filtering.StickerFilter

Bases: djmessenger.filtering.BaseFilter

Pass if messaging is a STICKER and the id is within STICKER_IDS

STICKER_IDS = ()
should_pass(messaging)
class djmessenger.filtering.ThumbUpFilter

Bases: djmessenger.filtering.StickerFilter

STICKER_IDS = ('810', '814', '822')
class djmessenger.filtering.TimeFilter(start_time, end_time)

Bases: djmessenger.filtering.BaseFilter

Filter that passes if the messaging timestamp is within the predefined time period

An example in policy

{
    "name": "djmessenger.filtering.TimeFilter",
    "args": {
        "start_time": "2016-1-1T00:00:00Z-0800",
        "end_time": "2017-1-1T01:00:00Z-0800"
    }
}
FORMAT = '%Y-%m-%dT%H:%M:%SZ%z'
should_pass(messaging)

djmessenger.handling module

Handling Module

Handling module provides abstract class and some implementation for handling a djmessenger.receiving.Messaging object. Handling means to do internal operations against the Messaging object, eg. save something into database, and etc

BaseHandler

Defines handle(messaging) which need to be overridden by subclasses

In handle(), you just perform operations on the data provided by messaging

class djmessenger.handling.BaseHandler

Bases: abc.ABC

BaseHandler is an abstract base class to

Actually handle it by adding something to database, or other internal work

handle(messaging)

Actually handles the messaging

Parameters:messaging (djmessenger.receiving.Messaging) – A Messaging object to handle
Returns:nothing
class djmessenger.handling.BasePayloadHandler

Bases: djmessenger.handling.BaseHandler

Postback and QuickReply contains payload, and in order to support request chaining, we need to provide a default base class for Postback and QuickReply.

Since the payload in Postback and QuickReply is merely a simple string limited to 1000 chars, we can utilize this space to send some bookkeeping info to achieve request chaining.

We are going to make the payload (which is a plain text) looks like a valid json object so that we can deserialize it back to a dict and then we can figure out which handler was the sender, then do corresponding actions

get_payload(messaging)

Payload class must be a subclass of djmessenger.utils.payload.Payload, and the class defines an attribute payload_class, we can simply load the class from this fully qualified class name

Returns:an instance of the subclass of Payload
Return type:an instance of the subclass of Payload
get_payload_string_from_messaging(messaging)

Returns payload contained in djmessenger.receiving.Messaging

Returns:the corresponding payload string from Messaging
Return type:str
class djmessenger.handling.BasePostbackHandler

Bases: djmessenger.handling.BasePayloadHandler

A base class to be extended by subclass to handle custom Postback Payload

get_payload_string_from_messaging(messaging)
Returns:The payload portion from Messaging
Return type:str
handle(messaging)
class djmessenger.handling.BaseQuickReplyHandler

Bases: djmessenger.handling.BasePayloadHandler

A base class to be extended by subclasses to handle custom QuickReply payload

get_payload_string_from_messaging(messaging)
get_text(messaging)

quick reply will come with text which is the quick reply title

Returns:
handle(messaging)
class djmessenger.handling.LocationHandler

Bases: djmessenger.handling.BaseHandler

If the user sends a location to the BOT (by click on the map pin icon next to thumb up), this handler saves this coordinates to the database

handle(messaging)
class djmessenger.handling.SaveMessagingHandler

Bases: djmessenger.handling.BaseHandler

This handler saves the messaging into the database for further reference

handle(messaging)
class djmessenger.handling.ThumbUpHandler

Bases: djmessenger.handling.BaseHandler

Handles when the user sends a thumb up

handle(messaging)
class djmessenger.handling.UserProfileHandler

Bases: djmessenger.handling.BaseHandler

Every messaging has sender.id, based on settings.DJM_SAVE_USER_PROFILE, this handler save user profile into database using models.FBUserProfile.

If DJM_SAVE_USER_PROFILE was True, we fetch user profile using graph API; otherwise we only save user psid to the database

handle(messaging)

djmessenger.models module

Django model definition

class djmessenger.models.FBUserProfile(*args, **kwargs)

Bases: django.db.models.base.Model

This FBUserProfile class is to represent a user that sent a message to us via Facebook Messenger, from the message relayed by Facebook, we can look up user details which will be stored here

exception DoesNotExist

Bases: django.core.exceptions.ObjectDoesNotExist

exception FBUserProfile.MultipleObjectsReturned

Bases: django.core.exceptions.MultipleObjectsReturned

FBUserProfile.date_joined

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

FBUserProfile.first_name

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

FBUserProfile.gender

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

FBUserProfile.get_next_by_date_joined(*moreargs, **morekwargs)
FBUserProfile.get_previous_by_date_joined(*moreargs, **morekwargs)
FBUserProfile.is_active

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

FBUserProfile.last_name

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

FBUserProfile.locale

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

FBUserProfile.objects = <django.db.models.manager.Manager object>
FBUserProfile.profile_pic

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

FBUserProfile.psid

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

FBUserProfile.reply_set

Accessor to the related objects manager on the reverse side of a many-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

parent.children is a ReverseManyToOneDescriptor instance.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

FBUserProfile.thumbups

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

FBUserProfile.timezone

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

FBUserProfile.userlocation_set

Accessor to the related objects manager on the reverse side of a many-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

parent.children is a ReverseManyToOneDescriptor instance.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

class djmessenger.models.Messaging(*args, **kwargs)

Bases: django.db.models.base.Model

A table to store djmessenger.receiving.Messaging

exception DoesNotExist

Bases: django.core.exceptions.ObjectDoesNotExist

exception Messaging.MultipleObjectsReturned

Bases: django.core.exceptions.MultipleObjectsReturned

Messaging.body

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

Messaging.id

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

Messaging.objects = <django.db.models.manager.Manager object>
Messaging.type

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

class djmessenger.models.Reply(*args, **kwargs)

Bases: django.db.models.base.Model

A table to store all replies

exception DoesNotExist

Bases: django.core.exceptions.ObjectDoesNotExist

exception Reply.MultipleObjectsReturned

Bases: django.core.exceptions.MultipleObjectsReturned

Reply.data

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

Reply.date_sent

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

Reply.get_next_by_date_sent(*moreargs, **morekwargs)
Reply.get_previous_by_date_sent(*moreargs, **morekwargs)
Reply.id

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

Reply.objects = <django.db.models.manager.Manager object>
Reply.recipient

Accessor to the related object on the forward side of a many-to-one or one-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

child.parent is a ForwardManyToOneDescriptor instance.

Reply.recipient_id

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

Reply.response

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

Reply.status_code

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

Reply.type

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

class djmessenger.models.UserLocation(*args, **kwargs)

Bases: django.db.models.base.Model

From the message user sent via Facebook to us, addition to saving the raw request body into RawBody, we try to see if the sent message is actually a location that contains lat and long, if yes, then we save it here

exception DoesNotExist

Bases: django.core.exceptions.ObjectDoesNotExist

exception UserLocation.MultipleObjectsReturned

Bases: django.core.exceptions.MultipleObjectsReturned

UserLocation.date_created

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

UserLocation.get_next_by_date_created(*moreargs, **morekwargs)
UserLocation.get_previous_by_date_created(*moreargs, **morekwargs)
UserLocation.id

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

UserLocation.latitude

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

UserLocation.longitude

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

UserLocation.mid

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

UserLocation.objects = <django.db.models.manager.Manager object>
UserLocation.seq

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

UserLocation.timestamp

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

UserLocation.url

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

UserLocation.user

Accessor to the related object on the forward side of a many-to-one or one-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

child.parent is a ForwardManyToOneDescriptor instance.

UserLocation.user_id

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

djmessenger.payload module

Payload

Payload object is being used in both handlers and repliers, it starts with you, as the BOT, replies the user buttons or quick replies, each of them may contain a payload.

Payload is represented in Facebook callback as a simple string, however, in order for BOT to better handle it, we are going to treat it as a valid json string.

A payload contains key-value pairs that are dependant to your business logic, as a result, you will need to write your own payload if you’d like to send buttons and replies.

Payload class provides a get_instance() classmethod that simply take a json string and try to deserialize it back to an instance of the actual subclass.

Here is a quick example, let’s say you want to display your products when the user sends you a simple text “products”, what you need to do is

  1. Define routing policy

    In your routing policy, specify djmessenger.filtering.SimpleTextRegexFilter and provide regex as “^products$” as a filter for SIMPLE_TEXT

  2. Custom Replier

    Write a custom replier which extends either djmessenger.replying.BaseButtonReplier or djmessenger.replying.BaseQuickReplyReplier and provide payload that contains your product info, something like

    Make sure you call super().__init__()
    class MyProductPayload(Payload):
        def __init__(self, name, price):
            super().__init__()
            self.name = name
            self.price = price
    

    when you’re replying, this payload will be serialized into a single string and sent along with the template.

    Please see djmessenger.replying.BaseButtonReplier and djmessenger.replying.BaseQuickReplyReplier for more details

    The main difference between buttons and quick replies are:

    1. Buttons can only have 3 at a time
    2. Quick Replies can have 10 at a time
    3. When user clicks on Buttons, it generates a djmessenger.receiving.Postback
    4. When user clicks on quick replies, it generates a djmessenger.receiving.QuickReply
  3. Custom handler

    If you want to do something when user clicks on the buttons or quick replies (which you most likely would, otherwise why sent buttons, right), you need to implement a custom handler which extends either djmessenger.handling.BaseQuickReplyHandler or djmessenger.handling.BasePostbackHandler.

    Both of them defines a method get_payload() which will return you an instance of MyProductPayload, at this point you know which user (PSID) clicks on which button (payload) and you can do something like saving to database

  4. Replier

    Then you can use built-in sender or custom sender again to send something back to the user

class djmessenger.payload.GetStartedPayload

Bases: djmessenger.payload.Payload

class djmessenger.payload.Payload

Bases: djmessenger.utils.serializable.Serializable, abc.ABC

Your customized Payload subclass must extend this class and MAKE SURE that you call super().__init__ in your __init__()

PAYLOAD_CLASS_ATTRIBUTE = 'payload_class'
get_class()
Returns:the Payload subclass
Return type:class
classmethod get_instance(json_data)

This class method takes either a string in json format or a dict that represents a subclass of Payload. Since all payload subclass must subclass Payload and each of them has payload_class defined, we can easily determine what is the exact payload class and load the data and return an instance of that subclass

Parameters:json_data (str or dict) – string or dict that represents the subclass of Payload
Returns:an instance of the subclass of Payload
Type:subclass of Payload
@raise ValueError: 1. json_data is empty
  1. json_data is neither str nor dict
  2. json_data load failed
  3. json_data load successfully but does not load as a dict
  4. loaded json_data but it doesn’t contain payload_class attribute
  5. unable to deserialize it back to the Payload subclass

@raise ImportError: load_class failed @raise AttributeError: load_class failed

is_valid()

Facebook restricts that payload string can not exceed 1000 chars

Returns:True if the serialized string is less than or equal to 1000; False otherwise
Return type:bool
class djmessenger.payload.PersistentMenuFivePayload

Bases: djmessenger.payload.Payload

class djmessenger.payload.PersistentMenuFourPayload

Bases: djmessenger.payload.Payload

class djmessenger.payload.PersistentMenuOnePayload

Bases: djmessenger.payload.Payload

class djmessenger.payload.PersistentMenuThreePayload

Bases: djmessenger.payload.Payload

class djmessenger.payload.PersistentMenuTwoPayload

Bases: djmessenger.payload.Payload

djmessenger.receiving module

# Receiving module

This module contains all classes that represent a Facebook callback. Basically this is just models to represent the json templates that Facebook would sent over as described here:

Facebook Webhook Reference

class djmessenger.receiving.AccountLinking(status, authorization_code='')

Bases: djmessenger.utils.serializable.Serializable

class djmessenger.receiving.AccountLinkingChecker(messaging)

Bases: djmessenger.receiving.MessagingChecker

check()
class djmessenger.receiving.Attachment(ttype, payload, url)

Bases: djmessenger.utils.serializable.Serializable

There are 2 types of Attachment payloads, LocationAttachmentPayload and MultimediaAttachmentPayload, so we are not providing _obj_map but need to override deserialize to look at self.type and determine which type of payload to deserialize to

classmethod deserialize(json_data)
class djmessenger.receiving.AttachmentType(name, description='')

Bases: djmessenger.utils.serializable.SerializableEnum

AUDIO = (AttachmentType) audio
FILE = (AttachmentType) file
IMAGE = (AttachmentType) image
LOCATION = (AttachmentType) location
VIDEO = (AttachmentType) video
members = {'audio': (AttachmentType) audio, 'location': (AttachmentType) location, 'image': (AttachmentType) image, 'file': (AttachmentType) file, 'video': (AttachmentType) video}
class djmessenger.receiving.AuthenticationChecker(messaging)

Bases: djmessenger.receiving.MessagingChecker

check()
class djmessenger.receiving.Callback(object='page', entry=[])

Bases: djmessenger.utils.serializable.Serializable

https://developers.facebook.com/docs/messenger-platform/webhook-reference

custom_obj_map = {'entry': [<class 'djmessenger.receiving.Entry'>, <class 'list'>]}
classmethod get_instance(request)
Parameters:request (django.core.handlers.wsgi.WSGIRequest) – HTTP Request object
Returns:instance of Callback
Return type:Callback
get_sender_id()

Each callback must have some Messaging, we should expect that we can always get a sender id

Returns:
class djmessenger.receiving.Coordinates(lat, llong)

Bases: djmessenger.utils.serializable.Serializable

class djmessenger.receiving.Delivery(watermark, seq, mids=[])

Bases: djmessenger.utils.serializable.Serializable

class djmessenger.receiving.Entry(iid, time, messaging=[])

Bases: djmessenger.utils.serializable.Serializable

https://developers.facebook.com/docs/messenger-platform/webhook-reference

custom_obj_map = {'messaging': [<class 'djmessenger.receiving.Messaging'>, <class 'list'>]}
class djmessenger.receiving.LocationAttachmentPayload(coordinates)

Bases: djmessenger.utils.serializable.Serializable

custom_obj_map = {'coordinates': [<class 'djmessenger.receiving.Coordinates'>, <class 'object'>]}
class djmessenger.receiving.Message(text, mid, seq, sticker_id=None, quick_reply=None, attachments=[], is_echo=False, app_id='', metadata='')

Bases: djmessenger.utils.serializable.Serializable

Each Messaging could have 1 Message object

custom_obj_map = {'attachments': [<class 'djmessenger.receiving.Attachment'>, <class 'list'>], 'quick_reply': [<class 'djmessenger.receiving.QuickReply'>, <class 'object'>]}
class djmessenger.receiving.MessageDeliveredChecker(messaging)

Bases: djmessenger.receiving.MessagingChecker

check()
class djmessenger.receiving.MessageReadChecker(messaging)

Bases: djmessenger.receiving.MessagingChecker

check()
class djmessenger.receiving.MessageReceivedChecker(messaging)

Bases: djmessenger.receiving.MessagingChecker

This check handles all types in MessagedReceived and MessageEcho

check()
class djmessenger.receiving.Messaging(sender, recipient, timestamp=1478999839, message=None, postback=None, optin=None, account_linking=None, delivery=None, read=None)

Bases: djmessenger.utils.serializable.Serializable

Each Entry contains multiple Messaging object, Messaging has different CallbackType, we are going to define this class so that it includes all possible objects and then when we got a json data, we just load them into the objects. After we deserialized json data into Messaging, we then determine what type of a Callback this is by looking at some fields and values using CallbackTypeChecker

custom_obj_map = {'message': [<class 'djmessenger.receiving.Message'>, <class 'object'>], 'delivery': [<class 'djmessenger.receiving.Delivery'>, <class 'object'>], 'optin': [<class 'djmessenger.receiving.Optin'>, <class 'object'>], 'sender': [<class 'djmessenger.receiving.Sender'>, <class 'object'>], 'read': [<class 'djmessenger.receiving.Read'>, <class 'object'>], 'postback': [<class 'djmessenger.receiving.Postback'>, <class 'object'>], 'recipient': [<class 'djmessenger.receiving.Recipient'>, <class 'object'>], 'account_linking': [<class 'djmessenger.receiving.AccountLinking'>, <class 'object'>]}
get_coordinates()
Returns:
Return type:Coordinates
get_postback_payload()
Returns:
Return type:str
get_psid()
get_quick_reply_payload()
get_receiving_type()

After loading the json data into this object, try to determine what type of callback this messaging is

Returns:
Return type:ReceivingType
get_sticker_id()
get_text()
Returns:
Return type:str
get_url()
Returns:
Return type:str
get_watermark()
class djmessenger.receiving.MessagingChecker(messaging)

Bases: abc.ABC

MessagingChecker is to check a messaging that ReceivingType it should be

check()
Returns:Corresponding CallbackType if it passed any check; None if nothing matches
Return type:ReceivingType
class djmessenger.receiving.MultimediaAttachmentPayload(url)

Bases: djmessenger.utils.serializable.Serializable

class djmessenger.receiving.Optin(ref)

Bases: djmessenger.utils.serializable.Serializable

class djmessenger.receiving.Postback(payload)

Bases: djmessenger.utils.serializable.Serializable

class djmessenger.receiving.PostbackReceivedChecker(messaging)

Bases: djmessenger.receiving.MessagingChecker

check()
class djmessenger.receiving.QuickReply(payload)

Bases: djmessenger.utils.serializable.Serializable

class djmessenger.receiving.Read(watermark, seq)

Bases: djmessenger.utils.serializable.Serializable

class djmessenger.receiving.ReceivingType(name, description='')

Bases: djmessenger.utils.serializable.SerializableEnum

ReceivingType defines all types that will be sent by Facebook

ACCOUNT_LINKING = (ReceivingType) ACCOUNT_LINKING
AUDIO = (ReceivingType) AUDIO
AUTHENTICATION = (ReceivingType) AUTHENTICATION
DEFAULT = (ReceivingType) DEFAULT
DELIVERED = (ReceivingType) DELIVERED
ECHO = (ReceivingType) ECHO
FILE = (ReceivingType) FILE
GET_STARTED_BUTTON = (ReceivingType) GET_STARTED_BUTTON
IMAGE = (ReceivingType) IMAGE
LOCATION = (ReceivingType) LOCATION
PERSISTENT_MENU_FIVE = (ReceivingType) PERSISTENT_MENU_FIVE
PERSISTENT_MENU_FOUR = (ReceivingType) PERSISTENT_MENU_FOUR
PERSISTENT_MENU_ONE = (ReceivingType) PERSISTENT_MENU_ONE
PERSISTENT_MENU_THREE = (ReceivingType) PERSISTENT_MENU_THREE
PERSISTENT_MENU_TWO = (ReceivingType) PERSISTENT_MENU_TWO
POSTBACK = (ReceivingType) POSTBACK
QUICK_REPLY = (ReceivingType) QUICK_REPLY
READ = (ReceivingType) READ
SIMPLE_TEXT = (ReceivingType) SIMPLE_TEXT
STICKER = (ReceivingType) STICKER
VIDEO = (ReceivingType) VIDEO
members = {'PERSISTENT_MENU_ONE': (ReceivingType) PERSISTENT_MENU_ONE, 'AUDIO': (ReceivingType) AUDIO, 'QUICK_REPLY': (ReceivingType) QUICK_REPLY, 'PERSISTENT_MENU_FIVE': (ReceivingType) PERSISTENT_MENU_FIVE, 'ECHO': (ReceivingType) ECHO, 'DEFAULT': (ReceivingType) DEFAULT, 'SIMPLE_TEXT': (ReceivingType) SIMPLE_TEXT, 'READ': (ReceivingType) READ, 'ACCOUNT_LINKING': (ReceivingType) ACCOUNT_LINKING, 'VIDEO': (ReceivingType) VIDEO, 'FILE': (ReceivingType) FILE, 'PERSISTENT_MENU_FOUR': (ReceivingType) PERSISTENT_MENU_FOUR, 'LOCATION': (ReceivingType) LOCATION, 'GET_STARTED_BUTTON': (ReceivingType) GET_STARTED_BUTTON, 'AUTHENTICATION': (ReceivingType) AUTHENTICATION, 'STICKER': (ReceivingType) STICKER, 'POSTBACK': (ReceivingType) POSTBACK, 'IMAGE': (ReceivingType) IMAGE, 'PERSISTENT_MENU_THREE': (ReceivingType) PERSISTENT_MENU_THREE, 'PERSISTENT_MENU_TWO': (ReceivingType) PERSISTENT_MENU_TWO, 'DELIVERED': (ReceivingType) DELIVERED}
class djmessenger.receiving.Recipient(iid)

Bases: djmessenger.utils.serializable.Serializable

Your page

class djmessenger.receiving.Sender(iid)

Bases: djmessenger.utils.serializable.Serializable

In Receiving messages, Sender represents the Facebook user who sent this message to your page

djmessenger.replying module

Replying Module

Similarly, this replying module is to represent the json templates that should be used when sending something back to the user based on Facebook reference:

https://developers.facebook.com/docs/messenger-platform/send-api-reference

class djmessenger.replying.AudioReplier(url)

Bases: djmessenger.replying.MultimediaReplier

Reply an Audio from url

sending_type = (ReplyingType) audio
class djmessenger.replying.BaseButtonReplier(localized_string)

Bases: djmessenger.replying.SimpleMessageReplier

Facebook restricts to have 3 buttons at a time

To reply a list of Button, you need to

  1. Define a subclass that extends djmessenger.payload.Payload, so that when user clicks on a button and another request calls back, we have a way to determine the origin by checking which subclass of Payload it has
  2. Define a subclass that extends BaseButtonReplier
  3. Define BUTTONS class variable like this
class MyButtonReplier(BaseButtonReplier):
    BUTTONS = {
       'button 1': 'https://www.google.com',
       'button 2': MyButtonPayload('button payload 2')
    }

The first button will open a new window that goes to the url; while the second button will trigger a postback request back which contains the payload

BUTTONS = {}
class Button(title, url='', payload=None)

Bases: djmessenger.utils.serializable.Serializable

BaseButtonReplier.LIMIT = 3
BaseButtonReplier.add_button(title, url='', payload=None)
classmethod BaseButtonReplier.deserialize(json_data)
BaseButtonReplier.get_message(messaging)
BaseButtonReplier.get_reply_type()
class djmessenger.replying.BaseQuickReplyReplier(localized_string)

Bases: djmessenger.replying.SimpleMessageReplier

Facebook restricts to have 10 quick replies at a time.

To reply a list of Quick Replies, you need to

  1. Define a subclass that extends djmessenger.payload.Payload, so that when user clicks on a QR and another request calls back, we have a way to determine the origin by checking which subclass of Payload it has
  2. Define a subclass that extends BaseQuickReplyReplier
  3. Define QUICK_REPLIES class variable like this
class MyQuickReplyReplier(BaseQuickReplyReplier):
    QUICK_REPLIES = {
       'qr 1': MyQuickReplyPayload('qr payload 1'),
       'qr 2': MyQuickReplyPayload('qr payload 2'),
       'qr 3': MyQuickReplyPayload('qr payload 3'),
    }
LIMIT = 10
QUICK_REPLIES = {}
class QuickReply(title='', payload=None)

Bases: djmessenger.utils.serializable.Serializable

BaseQuickReplyReplier.add_quick_reply(title, payload)

An entry of quick reply button is represented like this as Facebook defined

{
    "content_type":"text",
    "title":"Red",
    "payload":"DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_RED"
},

content_type must be “text”, so the arguments here are title and payload , payload must be a subclass of Payload

classmethod BaseQuickReplyReplier.deserialize(json_data)
BaseQuickReplyReplier.get_message(messaging)
BaseQuickReplyReplier.get_reply_type()
class djmessenger.replying.ButtonType(name, description='')

Bases: djmessenger.utils.serializable.SerializableEnum

POSTBACK = (ButtonType) postback
WEB_URL = (ButtonType) web_url
members = {'web_url': (ButtonType) web_url, 'postback': (ButtonType) postback}
class djmessenger.replying.CommonReplier

Bases: djmessenger.utils.serializable.Serializable

Base class for all repliers, 2 abstract methods need to be overridden

CommonReplier.get_message() CommonReplier.get_reply_type()

get_message(messaging)

Based on the attributes the class constructor constructs, this method returns the message body, the returned must be a dict and valid json object.

When construct the request json payload, if there is any text that
could be i18n’ed, please make sure to use

CommonReplier.preprocess_outgoing_string() to make sure the string is using correct locale

Returns:
Return type:dict
get_reply_type()

Return the SendingType that this Sender sends

Returns:
Return type:ReplyingType
notification_type = (NotificationType) REGULAR
static preprocess_outgoing_string(psid, localized_text, add_prefix=True)

This method take cares of any preprocessing of the outgoing text. More specifically, this method converts the text into the user’s locale, if available.

Parameters:
  • psid
  • localized_text (LocalizedString) –
  • add_prefix (bool) – whether prepend DJM_BOT_PREFIX to the start of text, you might want to use it when processing button text
Returns:

localized string

Return type:

str

reply(messaging)

Ask the replier to reply to the psid from the given messaging

sender_action = None
class djmessenger.replying.DefaultMessageReplier

Bases: djmessenger.replying.SimpleMessageReplier

Sends back simple text DJM_DEFAULT_SENDER_TEXT

class djmessenger.replying.FileReplier(url)

Bases: djmessenger.replying.MultimediaReplier

Reply a File from url

sending_type = (ReplyingType) file
class djmessenger.replying.ImageReplier(url)

Bases: djmessenger.replying.MultimediaReplier

Reply an Image from url

sending_type = (ReplyingType) image
class djmessenger.replying.MultimediaReplier(url)

Bases: djmessenger.replying.CommonReplier

Send back multimedia from a url

ReplyingType.IMAGE = ReplyingType(‘IMAGE’) ReplyingType.AUDIO = ReplyingType(‘AUDIO’) ReplyingType.VIDEO = ReplyingType(‘VIDEO’) ReplyingType.FILE = ReplyingType(‘FILE’)

get_message(messaging)
get_reply_type()
sending_type = None
class djmessenger.replying.NotificationType(name, description='')

Bases: djmessenger.utils.serializable.SerializableEnum

NO_PUSH = (NotificationType) NO_PUSH
REGULAR = (NotificationType) REGULAR
SILEN_PUSH = (NotificationType) SILEN_PUSH
members = {'NO_PUSH': (NotificationType) NO_PUSH, 'SILEN_PUSH': (NotificationType) SILEN_PUSH, 'REGULAR': (NotificationType) REGULAR}
class djmessenger.replying.ReplyAction(name, description='')

Bases: djmessenger.utils.serializable.SerializableEnum

MARK_SEEN = (ReplyAction) mark_seen
TYPING_OFF = (ReplyAction) typing_off
TYPING_ON = (ReplyAction) typing_on
members = {'typing_off': (ReplyAction) typing_off, 'typing_on': (ReplyAction) typing_on, 'mark_seen': (ReplyAction) mark_seen}
class djmessenger.replying.ReplyActionReplier(action)

Bases: djmessenger.replying.CommonReplier

Send a ReplyAction

get_message(messaging)
get_reply_type()
class djmessenger.replying.ReplyingType(name, description='')

Bases: djmessenger.utils.serializable.SerializableEnum

AUDIO = (ReplyingType) audio
BUTTON = (ReplyingType) button
FILE = (ReplyingType) file
IMAGE = (ReplyingType) image
QUICK_REPLY = (ReplyingType) quick_reply
SENDER_ACTION = (ReplyingType) sender_action
SIMPLE_TEXT = (ReplyingType) simple_text
VIDEO = (ReplyingType) video
members = {'image': (ReplyingType) image, 'simple_text': (ReplyingType) simple_text, 'quick_reply': (ReplyingType) quick_reply, 'sender_action': (ReplyingType) sender_action, 'audio': (ReplyingType) audio, 'video': (ReplyingType) video, 'file': (ReplyingType) file, 'button': (ReplyingType) button}
class djmessenger.replying.SimpleMessageReplier(localized_string)

Bases: djmessenger.replying.CommonReplier

Send a simple text message

custom_obj_map = {'localized_string': (<class 'djmessenger.utils.utils.LocalizedString'>, <class 'object'>)}
get_message(messaging)
get_reply_type()
class djmessenger.replying.VideoReplier(url)

Bases: djmessenger.replying.MultimediaReplier

Reply a Video from url

sending_type = (ReplyingType) video

djmessenger.routing module

In a nutshell, the overall flow works like this

  1. receiving module converts incoming request body to a Callback instance
  2. Each Callback instance contains multiple Entry and each Entry contains multiple Messaging
  3. For each Messaging, we are going to apply this routing policy

Each routing policy contains

  1. A list of Rule

  2. A rule contains a list of filters, a list of handlers and a list of repliers

    2.1 filters are responsible for determining whether the given Messaging

    is applicable for further handling, a Messaging object must pass all listed filters in order to reach handlers

    2.2 handlers perform internal operations against the Messaging, such like

    saving something into database and etc

    2.3 repliers reply something back to the user

See djmessenger.utils.default_routing_policy for sample routing policy and more details

class djmessenger.routing.Policy(rules=[])

Bases: djmessenger.utils.serializable.Serializable

A Policy is the most important component in djmessenger. A Policy defines multiple Rule and when we got message from customer, we simply Policy.apply() the message

apply(messaging)

Apply this Policy to the given messaging instance

Parameters:messaging (djmessenger.receiving.Messaging) – An instance of Messaging class
custom_obj_map = {'rules': [<class 'djmessenger.routing.Rule'>, <class 'list'>]}
get_default_rule()

There can only be 1 Rule that has type DEFAULT, if there were multiple, return the first one; return empty list if not found.

The filters, handlers and repliers defined in DEFAULT Rule will be applied on all Rules

classmethod get_instance(json_data)

Given a json string, deserialize it and return a Policy

Returns:Policy
Return type:Policy
get_rules(rtype)
class djmessenger.routing.Rule(ttype, name='', filters=[], handlers=[], repliers=[])

Bases: djmessenger.utils.serializable.Serializable

A Rule is a class that will be applied to a Messaging instance. Each Rule contains a list of filters, a list of handlers and a list of repliers.

Filters take a Messaging and determine whether this Messaging should proceed further, if any of the Filters returns False, this Rule will be skipped.

See djmessenger.utils.default_routing_policy for sample routing policy and more details

custom_obj_map = {'filters': [<class 'djmessenger.routing.TargetFilterClass'>, <class 'list'>], 'repliers': [<class 'djmessenger.routing.TargetReplierClass'>, <class 'list'>], 'handlers': [<class 'djmessenger.routing.TargetHandlerClass'>, <class 'list'>]}
get_filter_instances()
get_filter_wrappers()
Returns:A list of TargetFilterClass instances which is a wrapper for BaseFilter
get_handler_instances()
get_handler_wrappers()
Returns:A list of TargetHandlerClass instances which is a wrapper for BaseHandler
get_receiving_type()

Each Rule defines a djmessenger.receiving.ReceivingType, this method returns it

Return type:ReceivingType
get_replier_instances()
get_replier_wrappers()
Returns:A list of TargetReplierClass instances which is a wrapper for CommonReplier
class djmessenger.routing.TargetClass(name, args={})

Bases: djmessenger.utils.serializable.Serializable

This class is a wrapper for filter, handler and replier which were defined in the policy file. When we are reading the policy file, we will first deserialize each dict using this class and this class is responsible for determining the exact target class and return an instance of it

BASE_CLASS = None
get_args()
get_class()

Loads and return the exact class from self.name

Returns:A class
Return type:class
get_instance()

Return an instance of the target class, which will be an instance of subclass of either djmessenger.filtering.BaseFilter, djmessenger.handling.BaseHandler or djmessenger.replying.CommonReplier

Return type:object
class djmessenger.routing.TargetFilterClass(name, args={})

Bases: djmessenger.routing.TargetClass

BASE_CLASS

alias of BaseFilter

class djmessenger.routing.TargetHandlerClass(name, args={})

Bases: djmessenger.routing.TargetClass

BASE_CLASS

alias of BaseHandler

class djmessenger.routing.TargetReplierClass(name, args={})

Bases: djmessenger.routing.TargetClass

BASE_CLASS

alias of CommonReplier

djmessenger.settings module

djmessenger.settings.DJM_BOT_PREFIX = <django.utils.functional.lazy.<locals>.__proxy__ object>

Prefix this string to all text messages sent to users

djmessenger.settings.DJM_BUSINESS_ADDRESS = ''

This address is where your business is located at

djmessenger.settings.DJM_DEFAULT_SENDER_TEXT = 'Thanks for your message'

A sender named djmessenger.sending.DefaultSender which is a SimpleTextSender you can define your message here and directly use it in DJM_ROUTING_POLICY

djmessenger.settings.DJM_ENDPOINT = 'aef40e8e2b258e647fe84655eab910a7a70bc0031e382f01ba'

The endpoint that Facebook will relay the callback message to also being used to setup webhook

djmessenger.settings.DJM_ENDPOINT_VERIFY_TOKEN = 'djmessenger_verify_token'

Verify Token to be used when verifying endpoint in developer.facebook.com

djmessenger.settings.DJM_PAGE_ACCESS_TOKEN = 'EAABtMkLqTLoBANwSkJxgqhkDtZBD9QLlzT4YW8JvxvzauC7nkaTtNRkqetF32mcTuwfQjtpm1cmZBx8HttEYLJ3MFDjeg8SLf6ZA6o84V0540McEEYHuoi7MZBHmAxvT08Kq5Iizj3uD0KqZCfUEGqwId4v5gAvXvifd7mw5TRQZDZD'

Facebook Page Access Token, get it from developers.facebook.com

djmessenger.settings.DJM_ROUTING_POLICY = {'rules': [{'type': 'DEFAULT', 'filters': [{'args': {'start_time': '2016-1-1T00:00:00Z-0800', 'end_time': '2017-1-1T01:00:00Z-0800'}, 'name': 'djmessenger.filtering.TimeFilter'}], 'name': 'default rule', 'handlers': [{'name': 'djmessenger.handling.UserProfileHandler'}, {'name': 'djmessenger.handling.SaveMessagingHandler'}]}, {'type': 'STICKER', 'filters': [{'name': 'djmessenger.filtering.ThumbUpFilter'}], 'repliers': [{'args': {'localized_string': {'translations': {'zh_TW': '謝謝您的讚'}, 'base_string': 'Thank you for your thumb!!!'}}, 'name': 'djmessenger.replying.SimpleMessageReplier'}, {'args': {'url': 'https://dl.dropboxusercontent.com/u/717667/icons/betatesting.png'}, 'name': 'djmessenger.replying.ImageReplier'}], 'name': 'ThumbUp Rule', 'handlers': [{'name': 'djmessenger.handling.ThumbUpHandler'}]}, {'type': 'SIMPLE_TEXT', 'filters': [{'args': {'regex': '^你好$'}, 'name': 'djmessenger.filtering.SimpleTextRegexFilter'}], 'repliers': [{'args': {'localized_string': {'translations': {'en_US': 'Hello to you, too!'}, 'base_string': '您也好'}}, 'name': 'djmessenger.replying.SimpleMessageReplier'}], 'name': 'Hello Chinese Rule'}, {'type': 'SIMPLE_TEXT', 'filters': [{'args': {'regex': '^hi$'}, 'name': 'djmessenger.filtering.SimpleTextRegexFilter'}], 'repliers': [{'args': {'localized_string': {'translations': {'zh_TW': '您也好'}, 'base_string': 'Hi you, too!'}}, 'name': 'djmessenger.replying.SimpleMessageReplier'}], 'name': 'Hi Rule'}, {'type': 'SIMPLE_TEXT', 'filters': [{'args': {'regex': '^buttons$'}, 'name': 'djmessenger.filtering.SimpleTextRegexFilter'}], 'repliers': [{'args': {'localized_string': {'translations': {'zh_TW': '請選擇一個按鈕'}, 'base_string': 'Please choose a button'}}, 'name': 'testapp.sending.MyButtonSender'}], 'name': 'buttons Rule'}, {'type': 'LOCATION', 'filters': [{'name': 'djmessenger.filtering.LocationFilter'}], 'name': 'Location Rule', 'handlers': [{'name': 'djmessenger.handling.LocationHandler'}]}, {'type': 'PERSISTENT_MENU_ONE', 'repliers': [{'args': {'localized_string': {'translations': {'zh_TW': '這是幫助訊息'}, 'base_string': 'This is help info'}}, 'name': 'djmessenger.replying.SimpleMessageReplier'}, {'args': {'localized_string': {'translations': {'zh_TW': '請選擇快速回覆'}, 'base_string': 'Please choose a QR'}}, 'name': 'testapp.sending.MyQuickReplySender'}], 'name': 'PM1 Rule'}, {'type': 'QUICK_REPLY', 'repliers': [{'args': {'localized_string': {'translations': {'zh_TW': '謝謝您的快速回覆'}, 'base_string': 'Thanks for the quick reply'}}, 'name': 'djmessenger.replying.SimpleMessageReplier'}], 'name': 'QR1 Rule', 'handlers': [{'name': 'testapp.handling.MyQuickReplyHandler'}]}]}

DJM_ROUTING_POLICY defines the lifecycle of a message being received, handling it and lastly send some response back. In the following format, each router represents a type of message received, handlers represent which handlers should be used to handle this type of message and lastly which senders should be used to send the response back.

See djmessenger.utils.default_routing_policy for more details

djmessenger.settings.DJM_SAVE_USER_PROFILE = True

Whether DJM should automatically fetch and save user profile for any user that sends message to the page and observed by BOT, default to True

djmessenger.settings.DJM_THREAD_ENABLE_AUTO_CONFIG = False

If set to True, djmessenger will send POST request to configure thread automatically. If set to False, you need to configure it by using management commands

djmessenger.settings.DJM_THREAD_ENABLE_GET_STARTED_BUTTON = True

https://developers.facebook.com/docs/messenger-platform/thread-settings/get-started-button Whether to enable get started button feature

djmessenger.settings.DJM_THREAD_GREETINGS_TEXT = <django.utils.functional.lazy.<locals>.__proxy__ object>

https://developers.facebook.com/docs/messenger-platform/thread-settings/greeting-text

  1. length must be <= 160
  2. only first time visitor sees this greeting text

djmessenger.urls module

djmessenger URL Configuration

The urlpatterns list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.9/topics/http/urls/

Examples: Function views

  1. Add an import: from my_app import views
  2. Add a URL to urlpatterns: url(r’^$’, views.home, name=’home’)
Class-based views
  1. Add an import: from other_app.views import Home
  2. Add a URL to urlpatterns: url(r’^$’, Home.as_view(), name=’home’)
Including another URLconf
  1. Import the include() function: from django.conf.urls import url, include
  2. Add a URL to urlpatterns: url(r’^blog/’, include(‘blog.urls’))

djmessenger.views module

class djmessenger.views.DJMBotView(**kwargs)

Bases: django.views.generic.base.View

dispatch(request, *args, **kwargs)
get(request, *args, **kwargs)

This will be called when Facebook verifies the endpoint

post(request, *args, **kwargs)

All Facebook callback will reach here

Module contents

djmessenger.get_git_changeset()

Returns a numeric identifier of the latest git changeset. The result is the UTC timestamp of the changeset in YYYYMMDDHHMMSS format. This value isn’t guaranteed to be unique, but collisions are very unlikely, so it’s sufficient for generating the development version numbers. TODO: Check if we can rely on services like read-the-docs to pick this up.

djmessenger.get_version(version=None)

Returns a PEP 386-compliant version number from VERSION.