Ejemplo n.º 1
0
def replace_auth_token_view():
    try:
        data = json.loads(flask.request.get_data().decode('utf-8'))
    except Exception as error:
        logging.error('input data parse error {}'.format(error))
        data = {}

    name = data.get('name')
    avatar = data.get('avatar')
    auth_token = data.get('token')
    webhook = data.get('webhook')

    if auth_token is not None and name is not None and avatar is not None:
        try:

            viberbot_api = Api(
                BotConfiguration(name=name,
                                 avatar=avatar,
                                 auth_token=auth_token))
            viberbot_api.set_webhook(url=webhook)

            resp = flask.jsonify(message='Auth token успешно заменен',
                                 account=viberbot_api.get_account_info())
            resp.status_code = 200
            return resp

        except Exception as error:
            logging.error('replace auth token error: {}'.format(error))
            resp = flask.jsonify(error='Auth token не удалось замененить ')
            resp.status_code = 404
            return resp

    resp = flask.jsonify(message='некорректные входные данные {}'.format(
        flask.request.get_data()))
    resp.status_code = 404
    return resp
Ejemplo n.º 2
0
class Viber(BaseMessenger):
    """
    IM connector for Viber Bot API
    """

    # region Interface

    def __init__(self, token: str, **kwargs):
        super().__init__(token, **kwargs)

        self.bot = Api(
            BotConfiguration(
                auth_token=token,
                name=kwargs.get('name'),
                avatar=kwargs.get('avatar'),
            ))

    def enable_webhook(self, url: str, **kwargs):
        return self.bot.set_webhook(url=url)

    def disable_webhook(self):
        return self.bot.unset_webhook()

    def get_account_info(self) -> Dict[str, Any]:
        # data = {
        #    "status":0,
        #    "status_message":"ok",
        #    "id":"pa:75346594275468546724",
        #    "name":"account name",
        #    "uri":"accountUri",
        #    "icon":"http://example.com",
        #    "background":"http://example.com",
        #    "category":"category",
        #    "subcategory":"sub category",
        #    "location":{
        #       "lon":0.1,
        #       "lat":0.2
        #    },
        #    "country":"UK",
        #    "webhook":"https://my.site.com",
        #    "event_types":[
        #       "delivered",
        #       "seen"
        #    ],
        #    "subscribers_count":35,
        #    "members":[
        #       {
        #          "id":"01234567890A=",
        #          "name":"my name",
        #          "avatar":"http://example.com",
        #          "role":"admin"
        #       }
        #    ]
        # }
        try:
            data = self.bot.get_account_info()
        except Exception as err:
            raise MessengerException(err)

        return {
            'id': data.get('id'),
            'username': data.get('name'),
            'uri': data.get('uri'),  # check this
            'info': data
        }

    def get_user_info(self, user_id: str, **kwargs) -> Dict[str, Any]:
        # data = {
        #   "id":"01234567890A=",
        #   "name":"John McClane",
        #   "avatar":"http://avatar.example.com",
        #   "country":"UK",
        #   "language":"en",
        #   "primary_device_os":"android 7.1",
        #   "api_version":1,
        #   "viber_version":"6.5.0",
        #   "mcc":1,
        #   "mnc":1,
        #   "device_type":"iPhone9,4"
        # }
        try:
            data = self.bot.get_user_details(user_id)
        except Exception as err:
            if 'failed with status: 12' in str(err):
                raise RequestsLimitExceeded(err)
            raise MessengerException(err)

        return {
            'id': data.get('id'),
            'username': data.get('name'),
            'avatar': data.get('avatar'),
            'info': data,
        }

    def parse_message(self, request: HttpRequest) -> Message:
        # Verify signature
        sign = request.META.get('HTTP_X_VIBER_CONTENT_SIGNATURE')
        data = json.loads(request.body)
        if not self.bot.verify_signature(request.body, sign):
            raise MessengerException(f'Viber message not verified; '
                                     f'Data={data}; Sign={sign};')

        return self._from_viber_message(self.bot.create_request(data))

    def send_message(self, receiver: str,
                     messages: Union[Message, List[Message]]) -> List[str]:
        if isinstance(messages, MessageList):
            messages = messages.as_list()
        elif isinstance(messages, Message):
            messages = [messages]

        vb_messages = []
        for message in messages:
            vb_messages.append(self._to_viber_message(message))

        try:
            return self.bot.send_messages(receiver, vb_messages)
        except Exception as err:
            if 'failed with status: 6, message: notSubscribed' in str(err):
                raise NotSubscribed(err)
            raise MessengerException(err)

    def welcome_message(self, text: str) -> Union[str, Dict[str, Any], None]:
        return {
            "sender": {
                "name": self.name,
                "avatar": self.avatar_url
            },
            "type": "text",
            "text": text
        }

    # endregion

    # region Help methods

    @staticmethod
    def _from_viber_message(vb_request: ViberRequest) -> Message:
        if isinstance(vb_request, vbr.ViberMessageRequest):
            assert isinstance(vb_request.message, TypedMessage)

            vb_message = vb_request.message
            if isinstance(vb_message, vbm.TextMessage):
                if 'btn-' in vb_message.text:
                    return Button(id=vb_request.message_token,
                                  user_id=vb_request.sender.id,
                                  timestamp=vb_request.timestamp,
                                  command=vb_message.text)
                return Text(id=vb_request.message_token,
                            user_id=vb_request.sender.id,
                            timestamp=vb_request.timestamp,
                            text=vb_message.text)
            elif isinstance(vb_message, vbm.PictureMessage):
                return Picture(id=vb_request.message_token,
                               user_id=vb_request.sender.id,
                               timestamp=vb_request.timestamp,
                               file_url=vb_message.media)
            elif isinstance(vb_message, vbm.VideoMessage):
                return Video(id=vb_request.message_token,
                             user_id=vb_request.sender.id,
                             timestamp=vb_request.timestamp,
                             file_url=vb_message.media,
                             file_size=vb_message.size)
            elif isinstance(vb_message, vbm.FileMessage):
                return File(id=vb_request.message_token,
                            user_id=vb_request.sender.id,
                            timestamp=vb_request.timestamp,
                            file_url=vb_message.media,
                            file_size=vb_message.size)
            elif isinstance(vb_message, vbm.RichMediaMessage):
                return RichMedia(id=vb_request.message_token,
                                 user_id=vb_request.sender.id,
                                 timestamp=vb_request.timestamp,
                                 text=vb_message.alt_text,
                                 rich_media=vb_message.rich_media)
            elif isinstance(vb_message, vbm.ContactMessage):
                return Contact(id=vb_request.message_token,
                               user_id=vb_request.sender.id,
                               timestamp=vb_request.timestamp,
                               contact=vb_message.contact)
            elif isinstance(vb_message, vbm.LocationMessage):
                return Location(id=vb_request.message_token,
                                user_id=vb_request.sender.id,
                                timestamp=vb_request.timestamp,
                                location=vb_message.location)
            elif isinstance(vb_message, vbm.URLMessage):
                return Url(id=vb_request.message_token,
                           user_id=vb_request.sender.id,
                           timestamp=vb_request.timestamp,
                           url=vb_message.media)
            elif isinstance(vb_message, vbm.StickerMessage):
                return Sticker(id=vb_request.message_token,
                               user_id=vb_request.sender.id,
                               timestamp=vb_request.timestamp,
                               file_id=vb_message.sticker_id)
            return Text(id=vb_request.message_token,
                        user_id=vb_request.sender.id,
                        timestamp=vb_request.timestamp,
                        text=str(vb_message))
        elif isinstance(vb_request, vbr.ViberConversationStartedRequest):
            return Event(id=vb_request.message_token,
                         user_id=vb_request.user_id,
                         timestamp=vb_request.timestamp,
                         event_type=EType.START,
                         user_name=vb_request.user.name,
                         context=vb_request.context)
        elif isinstance(vb_request, vbr.ViberSubscribedRequest):
            return Event(id=vb_request.message_token,
                         user_id=vb_request.user_id,
                         timestamp=vb_request.timestamp,
                         event_type=EType.SUBSCRIBED,
                         user_name=vb_request.user.name)
        elif isinstance(vb_request, vbr.ViberUnsubscribedRequest):
            return Event(id=vb_request.message_token,
                         user_id=vb_request.user_id,
                         timestamp=vb_request.timestamp,
                         event_type=EType.UNSUBSCRIBED)
        elif isinstance(vb_request, vbr.ViberDeliveredRequest):
            return Event(id=vb_request.message_token,
                         user_id=vb_request.user_id,
                         timestamp=vb_request.timestamp,
                         event_type=EType.DELIVERED)
        elif isinstance(vb_request, vbr.ViberSeenRequest):
            return Event(id=vb_request.message_token,
                         user_id=vb_request.user_id,
                         timestamp=vb_request.timestamp,
                         event_type=EType.SEEN)
        elif isinstance(vb_request, vbr.ViberFailedRequest):
            log.warning(f'Client failed receiving message; Error={vb_request}')
            return Event(id=vb_request.message_token,
                         user_id=vb_request.user_id,
                         timestamp=vb_request.timestamp,
                         event_type=EType.START,
                         context=vb_request.desc)
        elif vb_request.event_type == 'webhook':
            return Event(timestamp=vb_request.timestamp)

        log.warning(f'ViberRequest type={type(vb_request)}; '
                    f'Object={vb_request};')
        return Text(timestamp=vb_request.timestamp, text=str(vb_request))

    def _to_viber_message(self, message: Message) -> VbMessage:
        kb = self._get_keyboard(message.buttons)

        if isinstance(message, Text):
            return vbm.TextMessage(text=message.text, keyboard=kb)
        if isinstance(message, Sticker):
            return vbm.StickerMessage(sticker_id=message.file_id, keyboard=kb)
        elif isinstance(message, Picture):
            return vbm.PictureMessage(media=message.file_url,
                                      text=message.text,
                                      keyboard=kb)
        elif isinstance(message, Video):
            return vbm.VideoMessage(media=message.file_url,
                                    size=message.file_size,
                                    text=message.text,
                                    keyboard=kb)
        elif isinstance(message, (File, Audio)):
            return vbm.FileMessage(media=message.file_url,
                                   size=message.file_size or 0,
                                   file_name=message.file_name or '',
                                   keyboard=kb)
        elif isinstance(message, Contact):
            contact = message.contact
            return vbm.ContactMessage(contact=contact, keyboard=kb)
        elif isinstance(message, Url):
            return vbm.URLMessage(media=message.url, keyboard=kb)
        elif isinstance(message, Location):
            location = message.location
            return vbm.LocationMessage(location=location, keyboard=kb)
        elif isinstance(message, RichMedia):
            rich_media = message.rich_media
            return vbm.RichMediaMessage(rich_media=rich_media,
                                        alt_text=message.text,
                                        keyboard=kb)

    @staticmethod
    def _get_keyboard(buttons: List[Button]) -> Optional[Dict[str, Any]]:
        # TODO do refactoring
        if not buttons:
            return None

        vb_buttons = []
        for button in buttons:
            # assert isinstance(button, Button), f'{button=} {type(button)}'
            vb_btn = {
                'Columns':
                2,  # TODO: how is it storage in Model?
                'Rows':
                1,
                'BgColor':
                '#aaaaaa',
                'ActionType':
                'reply',
                'ActionBody':
                button.command,
                'Text':
                '<font color="{clr}"><b>{text}'
                '</b></font>'.format(text=button.text, clr='#131313'),
                'TextVAlign':
                'middle',
                'TextHAlign':
                'center',
                'TextOpacity':
                60,
                'TextSize':
                'large',
                'TextPaddings': [12, 8, 8, 20],  # [up, left, right, bottom]
            }

            if hasattr(button, 'image'):
                domain = Site.objects.get_current().domain
                vb_btn.update({
                    'BgMedia': f'https://{domain}{button.image}',
                    'BgMediaScaleType': 'fill'
                })

            vb_buttons.append(vb_btn)

        return {
            'Type': 'keyboard',
            'BgColor': '#ffffff',
            'min_api_version': 6,
            'Buttons': vb_buttons,
        }
Ejemplo n.º 3
0
class Viber(ChatIface):
    def __init__(self, web_url, web_config=('0.0.0.0', 8080)):
        super().__init__()

        self.thread = None
        self.token = os.environ.get('VIBER_TOKEN')
        if self.token is None:
            raise Exception('VIBER_TOKEN env variable is nil.')
        self.bot_configuration = BotConfiguration(
            name=os.environ.get('VIBER_NAME'),
            avatar='https://static.thenounproject.com/png/363639-200.png',
            auth_token=self.token)
        self.api = None
        self.app = Flask(__name__)
        self.web_config = web_config
        self.web_url = web_url
        self.setup_routes()
        self.last_message = None
        self.initial_button_text = "I want to book a hotel"

    def run(self):
        web_config = self.web_config
        self.thread = threading.Thread(target=self.start)
        self.thread.start()
        self.api = Api(self.bot_configuration)
        logging.info("Setting viber hook to: %s", self.web_url)
        evtypes = self.api.set_webhook(
            self.web_url, webhook_events=['conversation_started', 'message'])
        viber_account = self.api.get_account_info()
        logging.info("Registered ev types: %s", evtypes)
        logging.info("Account info: %s", viber_account)

    def start(self):
        web_config = self.web_config
        self.app.run(host=web_config[0],
                     port=web_config[1],
                     debug=True,
                     use_reloader=False)

    #  Message handlers
    #

    # Conversation start allows only 1 message before a subscription
    def _on_start(self, user_id):
        viber = self.api
        d = self.get_dialog(user_id)
        g = d.start()
        d.on_searching(
            lambda details: self._callback_on_searching(user_id, details))
        keyboard_msg = self.get_initial_keyboard(user_id)._keyboard
        viber.send_messages(user_id, [
            TextMessage(text=g, keyboard=keyboard_msg),
        ])

    def _on_message(self, user_id, message):
        # Make sure our dialog is setup.
        d = self.get_dialog(user_id)
        d.on_searching(
            lambda details: self._callback_on_searching(user_id, details))
        try:
            # Process the message
            is_done, rz = self.process_message(user_id, message)
            r = [rx for rx in listify(rz) if rx is not None]

            # Send replies
            if is_done and r is not None and len(r) > 0:
                last_response = r[len(r) - 1]
                last_response.buttons = [self.initial_button_text]

            self.send_replies(user_id, r)
        except Exception as ex:
            tb = traceback.format_exc()
            logging.info(tb)
            logging.info(ex)
            self.send_replies(user_id, "Sorry can you try a different phrase?")

    def _callback_on_searching(self, user_id, details):
        viber = self.api
        logging.info("Starting search at %s", details)
        place = details['location'].capitalize()
        t = details['type']
        if len(t) == 0:
            txtmsg = TextMessage(
                text="Great. Here are a few places for you to stay in {0}..".
                format(place))
            viber.send_messages(user_id, [txtmsg])
        else:
            txtmsg = TextMessage(
                text="Great. I'll start searching for {0} in {1}..".format(
                    'placest to stay', place))
            viber.send_messages(user_id, [txtmsg])

    def send_img(self,
                 user_id,
                 rep: dialog.dialog.Reply,
                 keyboard: KeyboardMessage = None):
        viber = self.api
        imglist = rep.img
        if not isinstance(imglist, list):
            imglist = [imglist]
        img = imglist[0]
        if img is None:
            return
        img_url = img['url']
        k = None
        if keyboard is not None:
            k = keyboard._keyboard
        pmsg = PictureMessage(text=rep.text, media=img_url, keyboard=k)
        viber.send_messages(user_id, [pmsg])

    def send_keyboard(self, user_id, keyboard):
        viber = self.api
        try:
            viber.send_messages(user_id, [keyboard])
        except:
            tb = traceback.format_exc()
            logging.info(tb)
            logging.info(ex)

    def send_replies(self, user_id, replies):
        viber = self.api

        if not isinstance(replies, list): replies = [replies]
        for rep in replies:
            if isinstance(rep, str):
                rep = dialog.dialog.msg_reply(rep)
            reply_text = rep.str()
            if reply_text == "":
                reply_text = "Can you try again with a different phrase?"
            logging.info("REPL[%s]: %s", rep.type, rep)
            self.send_reply(rep, reply_text, user_id)

    def send_on_done(self, user_id):
        init_kbd = self.get_initial_keyboard(user_id)
        viber = self.api
        viber.send_messages(user_id, [init_kbd])

    def send_reply(self, rep, reply_text, user_id):
        viber = self.api
        if rep.type == 'place':
            # Send the image and a button for the user to confirm or reject
            kbd = self.get_place_keyboard(user_id, rep.buttons)
            if rep.img:
                self.send_img(user_id, rep, keyboard=kbd)
            else:
                txtmsg = TextMessage(text=str(reply_text), keyboard=kbd)
                viber.send_messages(user_id, [txtmsg])

        elif rep.type == 'place_list':
            logging.info("Reply itinerary: %s", reply_text)
            txtmsg = TextMessage(text=str(reply_text),
                                 keyboard=buttons_to_keyboard(rep.buttons))
            viber.send_messages(user_id, [txtmsg])

        elif rep.type == 'interest_question':
            txtmsg = TextMessage(text=str(reply_text),
                                 keyboard=buttons_to_keyboard(rep.buttons))
            viber.send_messages(user_id, [txtmsg])
        else:
            rkbd = buttons_to_keyboard(rep.buttons)
            logging.info("KBD: %s", rkbd)
            txtmsg = TextMessage(text=str(reply_text), keyboard=rkbd)
            viber.send_messages(user_id, [txtmsg])

    def setup_routes(self):
        app = self.app

        @app.route('/', methods=['POST'])
        def incoming():
            import json
            viber = self.api
            data = request.get_data()
            logging.info("received request. post data: {0}".format(data))
            # every viber message is signed, you can verify the signature using this method
            if not viber.verify_signature(
                    request.get_data(),
                    request.headers.get('X-Viber-Content-Signature')):
                return Response(status=403)
            request_dict = json.loads(data)
            # this library supplies a simple way to receive a request object
            viber_request = viber.parse_request(data)

            if isinstance(viber_request, ViberConversationStartedRequest):
                user_id = viber_request.user.id
                self._on_start(user_id)
            elif isinstance(viber_request, ViberSeenRequest):
                pass
            elif isinstance(viber_request, ViberDeliveredRequest):
                pass
            elif isinstance(viber_request, ViberMessageRequest):
                sender_id = viber_request.sender.id
                message = viber_request.message
                # We need unique messages
                if isinstance(message, TextMessage):
                    ts = int(request_dict['timestamp'])
                    is_old = (self.last_message is not None
                              and (self.last_message[2] == ts)
                              and self.last_message[1] == sender_id)
                    cr_pair = (message.text, sender_id, ts)
                    # logging.info("MSG DUMP: %s", cr_pair)
                    # logging.info("LAST DUMP: %s", self.last_message)
                    # logging.info("DUP: %s", is_old)
                    if not is_old:
                        self.last_message = cr_pair
                        self._on_message(sender_id, message.text)
                        # self.last_message = cr_pair

            elif isinstance(viber_request, ViberFailedRequest):
                logging.warn(
                    "client failed receiving message. failure: {0}".format(
                        viber_request))

            return Response(status=200)

        @app.route('/incoming', methods=['POST'])
        def incomingUrl():
            logging.debug("received request. post data: {0}".format(
                request.get_data()))
            # handle the request here
            return Response(status=200)

        @app.route('/health-check', methods=['GET'])
        def health():
            logging.debug("Health-check")
            # handle the request here
            return Response(status=200)

    def get_place_keyboard(self, user_id, additional_buttons=None):
        import json
        buttons = [{
            "Columns": 2,
            "Rows": 2,
            "Text": "<font color=\"#494E67\">Confirm</font>",
            "TextSize": "medium",
            "TextHAlign": "center",
            "TextVAlign": "middle",
            "ActionType": "reply",
            "ActionBody": "Yes",
            "BgColor": "#f7bb3f",
        }, {
            "Columns": 2,
            "Rows": 2,
            "Text": "<font color=\"#494E67\">Next</font>",
            "TextSize": "medium",
            "TextHAlign": "center",
            "TextVAlign": "middle",
            "ActionType": "reply",
            "ActionBody": "No",
            "BgColor": "#f6f7f9",
        }, {
            "Columns": 2,
            "Rows": 2,
            "Text": "<font color=\"#494E67\">Stop</font>",
            "TextSize": "medium",
            "TextHAlign": "center",
            "TextVAlign": "middle",
            "ActionType": "reply",
            "ActionBody": "Stop",
            "BgColor": "#f6f7f9",
        }]
        if additional_buttons:
            buttons.extend([{
                "Columns": 2,
                "Rows": 2,
                "Text": "<font color=\"#494E67\">" + b + "</font>",
                "ActionBody": b,
            } for b in additional_buttons])
        keyboard = {
            "DefaultHeight": True,
            "BgColor": "#FFFFFF",
            "Type": "keyboard",
            "Buttons": buttons
        }
        msg = KeyboardMessage(keyboard=keyboard)
        return msg

    def get_initial_keyboard(self, user_id):
        keyboard = {
            "Type":
            "keyboard",
            "Buttons": [{
                "Columns":
                6,
                "ActionType":
                "reply",
                "Rows":
                1,
                "Text":
                "<font color=\"#494E67\">" + self.initial_button_text +
                "</font>",
                "TextSize":
                "medium",
                "TextHAlign":
                "center",
                "TextVAlign":
                "middle",
                "ActionBody":
                self.initial_button_text,
            }]
        }
        msg = KeyboardMessage(keyboard=keyboard)
        return msg
Ejemplo n.º 4
0
import os
import logging

#获取当前目录
current_dir = os.path.abspath(os.path.dirname(__file__))

# 日志
logging.basicConfig(level=logging.INFO,
                    filename="%s/logs/viber_bot.log" % current_dir,
                    format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

bot_configuration = BotConfiguration(
    name='saMonitorBot',
    avatar='http://viber.com/avatar.jpg',
    auth_token='4a73d9dc1127d3a1-bdfac7760afa25ea-6cfb6ca1663b11eb')
viber = Api(bot_configuration)

logger.info(viber.get_account_info())

viber.send_messages('1111', ["Hello World!"])

# viber.set_webhook('https://www.baidu.com')

# 导入viber 信息模块
from viberbot.api.messages import (TextMessage, ContactMessage, PictureMessage,
                                   VideoMessage)
from viberbot.api.messages.data_types.contact import Contact

text_message = TextMessage(text="Hello, World!")
Ejemplo n.º 5
0
class Viber(BaseMessenger):
    """
    IM connector for Viber REST API
    """
    def __init__(self, token: str, **kwargs):
        super().__init__(token, **kwargs)

        self.bot = Api(
            BotConfiguration(
                auth_token=token,
                name=kwargs.get('name'),
                avatar=kwargs.get('avatar'),
            ))

    def enable_webhook(self, url: str, **kwargs):
        return self.bot.set_webhook(url=url)

    def disable_webhook(self):
        return self.bot.unset_webhook()

    def get_account_info(self) -> Dict[str, Any]:
        # {
        #    "status":0,
        #    "status_message":"ok",
        #    "id":"pa:75346594275468546724",
        #    "name":"account name",
        #    "uri":"accountUri",
        #    "icon":"http://example.com",
        #    "background":"http://example.com",
        #    "category":"category",
        #    "subcategory":"sub category",
        #    "location":{
        #       "lon":0.1,
        #       "lat":0.2
        #    },
        #    "country":"UK",
        #    "webhook":"https://my.site.com",
        #    "event_types":[
        #       "delivered",
        #       "seen"
        #    ],
        #    "subscribers_count":35,
        #    "members":[
        #       {
        #          "id":"01234567890A=",
        #          "name":"my name",
        #          "avatar":"http://example.com",
        #          "role":"admin"
        #       }
        #    ]
        # }
        data = self.bot.get_account_info()
        account_info = {
            'id': data.get('id'),
            'username': data.get('name'),
            'info': data
        }
        return account_info

    def get_user_info(self, user_id: str, **kwargs) -> Dict[str, Any]:
        # {
        #    "status":0,
        #    "status_message":"ok",
        #    "message_token":4912661846655238145,
        #    "user":{
        #       "id":"01234567890A=",
        #       "name":"John McClane",
        #       "avatar":"http://avatar.example.com",
        #       "country":"UK",
        #       "language":"en",
        #       "primary_device_os":"android 7.1",
        #       "api_version":1,
        #       "viber_version":"6.5.0",
        #       "mcc":1,
        #       "mnc":1,
        #       "device_type":"iPhone9,4"
        #    }
        # }
        data = self.bot.get_user_details(user_id).get('user')
        user_info = {
            'id': data.get('id'),
            'username': data.get('name'),
            'info': {
                'avatar': data.get('avatar'),
                'country': data.get('country'),
                'language': data.get('language'),
                'primary_device_os': data.get('primary_device_os'),
                'api_version': data.get('api_version'),
                'viber_version': data.get('viber_version'),
                'device_type': data.get('device_type'),
            }
        }
        return user_info

    def parse_message(self, request: Request) -> Message:
        # NOTE: There is no way to get the body
        #       after processing the request in DRF.
        # # Verify signature
        # sign = request.META.get('HTTP_X_VIBER_CONTENT_SIGNATURE')
        # if not self.bot.verify_signature(request.body, sign):
        #     raise IMApiException(f'Viber message not verified; '
        #                          f'Data={request.data}; Sign={sign};')

        # Parse message data in to viber types
        vb_request = create_request(request.data)

        try:
            return self._get_message(vb_request)
        except Exception as err:
            # TODO: remove this after development
            log.exception(f'Parse message error; Message={vb_request}; '
                          f'Error={err};')
            return Message(MessageType.UNDEFINED)

    @staticmethod
    def _get_message(vb_request: ViberRequest) -> Message:
        if isinstance(vb_request, ViberMessageRequest):
            if isinstance(vb_request.message, TextMessage):
                return Message(message_type=MessageType.TEXT,
                               message_id=vb_request.message_token,
                               user_id=vb_request.sender.id,
                               text=vb_request.message.text,
                               timestamp=vb_request.timestamp)
            elif isinstance(vb_request.message, PictureMessage):
                return Message(message_type=MessageType.PICTURE,
                               message_id=vb_request.message_token,
                               user_id=vb_request.sender.id,
                               image_url=vb_request.message.media,
                               timestamp=vb_request.timestamp)
            elif isinstance(vb_request.message, VideoMessage):
                return Message(message_type=MessageType.PICTURE,
                               message_id=vb_request.message_token,
                               user_id=vb_request.sender.id,
                               video_url=vb_request.message.media,
                               size=vb_request.message.size,
                               timestamp=vb_request.timestamp)
            else:
                return Message(message_type=MessageType.TEXT,
                               message_id=vb_request.message_token,
                               user_id=vb_request.sender.id,
                               text=vb_request.message,
                               timestamp=vb_request.timestamp)
        elif isinstance(vb_request, ViberConversationStartedRequest):
            return Message(message_type=MessageType.START,
                           message_id=vb_request.message_token,
                           user_id=vb_request.user.id,
                           user_name=vb_request.user.name,
                           timestamp=vb_request.timestamp,
                           context=vb_request.context)
        elif isinstance(vb_request, ViberSubscribedRequest):
            return Message(message_type=MessageType.SUBSCRIBED,
                           user_id=vb_request.user.id,
                           user_name=vb_request.user.name,
                           timestamp=vb_request.timestamp)
        elif isinstance(vb_request, ViberUnsubscribedRequest):
            return Message(message_type=MessageType.UNSUBSCRIBED,
                           user_id=vb_request.user_id,
                           timestamp=vb_request.timestamp)
        elif isinstance(vb_request, ViberDeliveredRequest):
            return Message(message_type=MessageType.DELIVERED,
                           message_id=vb_request.meesage_token,
                           user_id=vb_request.user_id,
                           timestamp=vb_request.timestamp)
        elif isinstance(vb_request, ViberSeenRequest):
            return Message(message_type=MessageType.SEEN,
                           message_id=vb_request.meesage_token,
                           user_id=vb_request.user_id,
                           timestamp=vb_request.timestamp)
        elif isinstance(vb_request, ViberFailedRequest):
            log.warning(f'Client failed receiving message; Error={vb_request}')
            return Message(message_type=MessageType.FAILED,
                           message_id=vb_request.meesage_token,
                           user_id=vb_request.user_id,
                           error=vb_request.desc)
        elif vb_request.event_type == 'webhook':
            return Message(message_type=MessageType.WEBHOOK,
                           timestamp=vb_request.timestamp)
        else:
            log.warning(f'VRequest Type={type(vb_request)}; '
                        f'Object={vb_request};')
            return Message(message_type=MessageType.UNDEFINED,
                           timestamp=vb_request.timestamp,
                           event_type=vb_request.event_type)
            # raise IMApiException('Failed parse message; '
            #                      'Request object={}'.format(viber_request))

    def send_message(self,
                     receiver: str,
                     message: str,
                     button_list: list = None,
                     **kwargs) -> str:
        kb = self._get_keyboard(button_list) if button_list else None

        if message:
            vb_message = TextMessage(text=message, keyboard=kb)
        else:
            vb_message = KeyboardMessage(keyboard=kb)

        try:
            return self.bot.send_messages(receiver, [vb_message])[0]
        except Exception as err:
            if str(err) == 'failed with status: 6, message: notSubscribed':
                raise NotSubscribed(err)
            raise MessengerException(err)

    def send_file(self,
                  receiver: str,
                  file_url: str,
                  file_size: int,
                  file_name: str,
                  file_type: str = None,
                  button_list: list = None,
                  **kwargs) -> str:
        kb = self._get_keyboard(button_list) if button_list else None

        if file_type == 'image':
            message = PictureMessage(media=file_url, keyboard=kb)
        elif file_type == 'video':
            message = VideoMessage(media=file_url, size=file_size, keyboard=kb)
        else:
            message = FileMessage(media=file_url,
                                  size=file_size,
                                  file_name=file_name,
                                  keyboard=kb)

        try:
            return self.bot.send_messages(receiver, [message])[0]
        except Exception as err:
            if str(err) == 'failed with status: 6, message: notSubscribed':
                raise NotSubscribed(err)
            raise MessengerException(err)

    def welcome_message(self, text: str) -> Dict[str, str]:
        return {
            "sender": {
                "name": self.name,
                "avatar": self.avatar_url
            },
            "type": "text",
            "text": text
        }

    @staticmethod
    def _get_keyboard(buttons: list):
        if not buttons:
            return None

        kb = {
            'Type': 'keyboard',
            'BgColor': '#ffffff',
            'min_api_version': 6,
            'Buttons': []
        }

        for button in buttons:
            # if not isinstance(button, Button):
            #     continue

            _btn = {
                'Columns':
                2,  # TODO: how is it storage in Model?
                'Rows':
                1,
                'BgColor':
                '#aaaaaa',
                'ActionType':
                'reply',
                'ActionBody':
                button.command,
                'Text':
                '<font color="{clr}"><b>{text}'
                '</b></font>'.format(text=button.text, clr='#131313'),
                'TextVAlign':
                'middle',
                'TextHAlign':
                'center',
                'TextOpacity':
                60,
                'TextSize':
                'large',
                'TextPaddings': [12, 8, 8, 20],  # [up, left, right, bottom]
            }

            try:
                if hasattr(button, 'image'):
                    _btn.update(
                        BgMedia=
                        f'https://bot.it-o.ru/static/img/{button.image}',
                        BgMediaScaleType='fill')
            except IndexError:
                pass

            kb['Buttons'].append(_btn)

        return kb