Exemplo n.º 1
0
    def test_switch_mode(self):
        bot_user = BotUser(**self.default_user_data)
        bot = EvernoteBot(self.config)
        with self.assertRaises(EvernoteBotException) as ctx:
            bot.switch_mode(bot_user, "invalid")
        self.assertEqual(str(ctx.exception), "Unknown mode 'invalid'")

        bot.api = mock.Mock()
        bot.api.sendMessage = mock.Mock()
        bot.switch_mode(bot_user, "multiple_notes")
        bot.api.sendMessage.assert_called_once_with(
            1, "The bot already in 'multiple_notes' mode.",
            "{\"hide_keyboard\": true}")

        bot.switch_mode_one_note = mock.Mock()
        bot.switch_mode(bot_user, "one_note")
        bot.switch_mode_one_note.assert_called_once()

        bot_user.bot_mode = "one_note"
        bot_user.evernote.shared_note_id = 123
        bot.api.sendMessage = mock.Mock()
        bot.switch_mode(bot_user, "multiple_notes")
        bot.api.sendMessage.assert_called_once_with(
            1, "The bot has switched to 'multiple_notes' mode.",
            "{\"hide_keyboard\": true}")
        self.assertIsNone(bot_user.evernote.shared_note_id)
        self.assertEqual(bot_user.bot_mode, "multiple_notes")
Exemplo n.º 2
0
def start_command(bot, message: Message):
    user_id = message.from_user.id
    user_data = bot.users.get(user_id)
    if not user_data:
        current_time = time()
        telegram_user = message.from_user
        user_data = {
            'id': user_id,
            'created': current_time,
            'last_request_ts': current_time,
            'bot_mode': bot.config.get('default_mode', 'multiple_notes'),
            'telegram': {
                'first_name': telegram_user.first_name,
                'last_name': telegram_user.last_name,
                'username': telegram_user.username,
                'chat_id': message.chat.id,
            },
            'evernote': {
                'access': {
                    'permission': 'basic'
                },
            },
        }
        bot.users.create(user_data)

    user = BotUser(**user_data)
    message_text = '''Welcome! It's bot for saving your notes to Evernote on fly.
Please tap on button below to link your Evernote account with bot.'''
    user.evernote.oauth = get_evernote_oauth_data(bot, user, message_text)
    bot.users.save(user.asdict())
Exemplo n.º 3
0
 def handle_state(self, bot_user: BotUser, message: Message):
     state = bot_user.state
     handlers_map = {
         'switch_mode': self.switch_mode,  # self.switch_mode()
         'switch_notebook': self.switch_notebook,  # self.switch_notebook()
     }
     state_handler = handlers_map[state]
     state_handler(bot_user, message.text)
     bot_user.state = None
     self.users.save(bot_user.asdict())
Exemplo n.º 4
0
 def handle_state(self, bot_user: BotUser, message: Message):
     state = bot_user.state
     handlers_map = {
         "switch_mode": self.switch_mode,  # self.switch_mode()
         "switch_notebook": self.switch_notebook,  # self.switch_notebook()
     }
     state_handler = handlers_map.get(state)
     if not state_handler:
         raise EvernoteBotException(f"Invalid state: {state}")
     state_handler(bot_user, message.text)
     bot_user.state = None
     self.users.save(bot_user.asdict())
Exemplo n.º 5
0
def evernote_oauth_callback(bot,
                            callback_key: str,
                            oauth_verifier: str,
                            access_type: str = "basic"):
    query = {"evernote.oauth.callback_key": callback_key}
    user_data = bot.users.get(query, fail_if_not_exists=True)
    user = BotUser(**user_data)
    chat_id = user.telegram.chat_id
    if not oauth_verifier:
        bot.api.sendMessage(
            chat_id, "We are sorry, but you have declined "
            "authorization.")
        return
    evernote_config = bot.config["evernote"]["access"][access_type]
    oauth = user.evernote.oauth
    try:
        oauth_params = {
            "token": oauth.token,
            "secret": oauth.secret,
            "verifier": oauth_verifier,
        }
        user.evernote.access.token = bot.evernote().get_access_token(
            evernote_config["key"],
            evernote_config["secret"],
            sandbox=bot.config.get("debug", True),
            **oauth_params)
    except TokenRequestDenied as e:
        bot.api.sendMessage(
            chat_id, "We are sorry, but we have some problems "
            "with Evernote connection. "
            "Please try again later.")
        raise e
    except Exception as e:
        bot.api.sendMessage(chat_id, "Unknown error. Please, try again later.")
        raise e
    user.evernote.access.permission = access_type
    user.evernote.oauth = None
    if access_type == "basic":
        bot.api.sendMessage(
            chat_id, "Evernote account is connected.\nFrom now "
            "you can just send a message and a note will be created.")
        default_notebook = bot.evernote(user).get_default_notebook()
        user.evernote.notebook = EvernoteNotebook(**default_notebook)
        mode = user.bot_mode.replace("_", " ").capitalize()
        bot.api.sendMessage(
            chat_id, "Current notebook: "
            f"{user.evernote.notebook.name}\nCurrent mode: {mode}")
    else:
        bot.switch_mode(user, "one_note")
    bot.users.save(user.asdict())
 def test_evernote_oauth_declined_auth(self):
     callback_key = hashlib.sha1(b"xxx").hexdigest()
     request = self.create_request({"key": callback_key, "access": "basic"})
     bot = request.app.bot
     bot.api = mock.Mock()
     bot.api.sendMessage = mock.Mock()
     bot_user = BotUser(**self.default_user_data)
     bot_user.evernote.oauth = EvernoteOauthData(token="token",
         secret="secret", callback_key=callback_key)
     bot.users.create(bot_user.asdict())
     evernote_oauth(request)
     bot.api.sendMessage.assert_called_once()
     self.assertEqual(bot.api.sendMessage.call_args[0][1],
         "We are sorry, but you have declined authorization.")
Exemplo n.º 7
0
 def test_switch_notebook(self):
     bot_user = BotUser(**self.default_user_data)
     bot = EvernoteBot(self.config)
     bot.api = mock.Mock()
     bot.api.sendMessage = mock.Mock()
     bot.evernote = mock.Mock()
     all_notebooks = [
         {
             "guid": "xxx",
             "name": "xxx"
         },
         {
             "guid": "zzz",
             "name": "zzz"
         },
     ]
     bot.evernote().get_all_notebooks = lambda query: list(
         filter(lambda nb: nb["name"] == query["name"], all_notebooks))
     with self.assertRaises(EvernoteBotException) as ctx:
         bot.switch_notebook(bot_user, "> www <")
     self.assertEqual(str(ctx.exception), "Notebook 'www' not found")
     bot.switch_notebook(bot_user, "zzz")
     self.assertEqual(bot_user.evernote.notebook.name, "zzz")
     self.assertEqual(bot_user.evernote.notebook.guid, "zzz")
     bot.api.sendMessage.assert_called_once()
     bot.switch_notebook(bot_user, "xxx")
     self.assertEqual(bot_user.evernote.notebook.guid, "xxx")
     bot.switch_notebook(bot_user, "xxx")
     self.assertEqual(bot_user.evernote.notebook.guid, "xxx")
Exemplo n.º 8
0
def evernote_oauth_callback(bot, params: OauthParams):
    query = {'evernote.oauth.callback_key': params.callback_key}
    user_data = bot.users.get(query, fail_if_not_exists=True)
    user = BotUser(**user_data)
    chat_id = user.telegram.chat_id
    if not params.verifier:
        bot.api.sendMessage(
            chat_id, 'We are sorry, but you have declined '
            'authorization.')
        return
    evernote_config = bot.config['evernote']['access'][params.access_type]
    oauth = user.evernote.oauth
    try:
        oauth_params = {
            'token': oauth.token,
            'secret': oauth.secret,
            'verifier': params.verifier,
        }
        user.evernote.access.token = bot.evernote().get_access_token(
            evernote_config['key'],
            evernote_config['secret'],
            sandbox=bot.config.get('debug', bot.config['debug']),
            **oauth_params)
    except TokenRequestDenied as e:
        bot.api.sendMessage(
            chat_id, 'We are sorry, but we have some problems '
            'with Evernote connection. '
            'Please try again later.')
        raise e
    except Exception as e:
        bot.api.sendMessage(chat_id, "Unknown error. Please, try again later.")
        raise e
    user.evernote.access.permission = params.access_type
    user.evernote.oauth = None
    if params.access_type == "basic":
        bot.api.sendMessage(
            chat_id, "Evernote account is connected.\nFrom now "
            "you can just send a message and a note will be created.")
        default_notebook = bot.evernote(user).get_default_notebook()
        user.evernote.notebook = EvernoteNotebook(**default_notebook)
        mode = user.bot_mode.replace("_", " ").capitalize()
        bot.api.sendMessage(
            chat_id, "Current notebook: "
            f"{user.evernote.notebook.name}\nCurrent mode: {mode}")
    else:
        bot.switch_mode(user, "one_note")
    bot.users.save(user.asdict())
Exemplo n.º 9
0
def start_command(bot, message: dict):
    user_id = message['from']['id']
    user_data = bot.users.get(user_id)
    if not user_data:
        current_time = time()
        telegram_user = message['from']
        user_data = {
            'id': user_id,
            'created': current_time,
            'last_request_ts': current_time,
            'bot_mode': 'multiple_notes',
            'telegram': {
                'first_name': telegram_user['first_name'],
                'last_name': telegram_user['last_name'],
                'username': telegram_user['username'],
                'chat_id': message['chat']['id'],
            },
            'evernote': {
                'access': {'permission': 'basic'},
            },
        }
        bot.users.create(user_data)

    user = BotUser(**user_data)
    message_text = '''Welcome! It's bot for saving your notes to Evernote on fly.
Please tap on button below to link your Evernote account with bot.'''

    chat_id = user.telegram.chat_id
    auth_button = {'text': 'Waiting for Evernote...', 'url': bot.url}
    inline_keyboard = json.dumps({'inline_keyboard': [[auth_button]]})
    status_message = bot.api.sendMessage(chat_id, message_text, inline_keyboard)
    key = bot.config['evernote']['access']['basic']['key']
    secret = bot.config['evernote']['access']['basic']['secret']
    oauth_callback = bot.config['oauth_callback']
    oauth_data = evernote.get_oauth_data(user.id, key, secret, oauth_callback, sandbox=bot.config.get('debug'))
    auth_button['text'] = 'Sign in with Evernote'
    auth_button['url'] = oauth_data['oauth_url']
    inline_keyboard = json.dumps({'inline_keyboard': [[auth_button]]})
    bot.api.editMessageReplyMarkup(chat_id, status_message['message_id'], inline_keyboard)
    user.evernote.oauth = EvernoteOauthData(
        token=oauth_data['oauth_token'],
        secret=oauth_data['oauth_token_secret'],
        callback_key=oauth_data['callback_key']
    )
    bot.users.save(user.asdict())
Exemplo n.º 10
0
 def on_text(self, message: Message):
     user_data = self.users.get(message.from_user.id)
     user = BotUser(**user_data)
     text = message.text
     telegram_link = message.get_telegram_link()
     if telegram_link:
         text = f'<div><p><a href="{telegram_link}">{telegram_link}</a></p><pre>{text}</pre></div>'
     title = self.get_caption(message) or '[Telegram bot]'
     self.save_note(user, '', title=title, html=text)
Exemplo n.º 11
0
 def test_get_evernote_api_object(self, sdk):
     bot = EvernoteBot(bot_config)
     api = bot.evernote()
     self.assertIsNotNone(api)
     self.assertTrue("default" in bot._evernote_apis_cache)
     bot_user = BotUser(**self.default_user_data)
     api = bot.evernote(bot_user)
     self.assertIsNotNone(api)
     self.assertEqual(len(bot._evernote_apis_cache), 2)
     self.assertTrue(bot_user.id in bot._evernote_apis_cache)
     for i in range(110):
         self.default_user_data["id"] = i
         bot_user = BotUser(**self.default_user_data)
         api = bot.evernote(bot_user)
         self.assertIsNotNone(api)
     self.assertEqual(len(bot._evernote_apis_cache), 100)
     self.assertFalse("default" in bot._evernote_apis_cache)
     self.assertFalse(1 in bot._evernote_apis_cache)
Exemplo n.º 12
0
def switch_mode_command(bot, message: Message):
    mode = message.text
    user_id = message.from_user.id
    user_data = bot.users.get(user_id)
    user = BotUser(**user_data)
    buttons = []
    for mode in ('one_note', 'multiple_notes'):
        title = mode.capitalize().replace('_', ' ')
        if user.bot_mode == mode:
            title = f'> {title} <'
        buttons.append({'text': title})
    keyboard = {
        'keyboard': [[b] for b in buttons],
        'resize_keyboard': True,
        'one_time_keyboard': True,
    }
    bot.api.sendMessage(user.telegram.chat_id, 'Please, select mode',
                        json.dumps(keyboard))
    user.state = 'switch_mode'
    bot.users.save(user.asdict())
Exemplo n.º 13
0
 def _save_file_to_evernote(self, file_id, file_size, message: Message):
     max_size = 20 * 1024 * 1024 # telegram restriction. We can't download any file that has size more than 20Mb
     if file_size > max_size:
         raise EvernoteBotException('File too big. Telegram does not allow to the bot to download files over 20Mb.')
     filename, short_name = download_telegram_file(self.api, file_id, self.config["tmp_root"])
     user_data = self.users.get(message.from_user.id)
     user = BotUser(**user_data)
     self._check_evernote_quota(user, file_size)
     title = message.caption or message.text[:20] or 'File'
     files = ({'path': filename, 'name': short_name},)
     self.save_note(user, text=message.text, title=title, files=files)
Exemplo n.º 14
0
def switch_mode_command(bot, message: dict):
    user_id = message['from']['id']
    user_data = bot.users.get(user_id)
    if not user_data:
        raise TelegramBotError("Unregistered user {0}. You've to send /start to register.")
    user = BotUser(**user_data)
    buttons = []
    for mode in ('one_note', 'multiple_notes'):
        title = mode.capitalize().replace('_', ' ')
        if user.bot_mode == mode:
            title = f'> {title} <'
        buttons.append({'text': title})
    keyboard = {
        'keyboard': [[b] for b in buttons],
        'resize_keyboard': True,
        'one_time_keyboard': True,
    }
    bot.api.sendMessage(user.telegram.chat_id, 'Please, select mode', json.dumps(keyboard))
    user.state = 'switch_mode'
    bot.users.save(user.asdict())
Exemplo n.º 15
0
def switch_notebook_command(bot, message: Message):
    user_id = message.from_user.id
    user_data = bot.users.get(user_id)
    user = BotUser(**user_data)
    all_notebooks = bot.evernote.get_all_notebooks(user.evernote.access.token)
    buttons = []
    for notebook in all_notebooks:
        name = notebook["name"]
        if name == user.evernote.notebook.name:
            name = f"> {name} <"
        buttons.append({"text": name})
    keyboard = {
        "keyboard": [[b] for b in buttons],
        "resize_keyboard": True,
        "one_time_keyboard": True,
    }
    bot.api.sendMessage(user.telegram.chat_id, "Please, select notebook",
                        json.dumps(keyboard))
    user.state = "switch_notebook"
    bot.users.save(user.asdict())
Exemplo n.º 16
0
 def get_evernote_api(self, user_id: int = None):
     user_id = user_id or self.ctx.get('user_id')
     if not user_id:
         raise Exception('`user_id` is not set')
     if not self._evernote_api.get(user_id):
         user_data = self.users.get(user_id)
         user = BotUser(**user_data)
         token = user.evernote.access.token
         self._evernote_api[user_id] = EvernoteApi(
             token, sandbox=self.config['debug'])
     return self._evernote_api[user_id]
Exemplo n.º 17
0
def switch_notebook_command(bot, message: dict):
    user_id = message['from']['id']
    user_data = bot.users.get(user_id)
    if not user_data:
        raise TelegramBotError("Unregistered user {0}. You've to send /start to register.")
    user = BotUser(**user_data)
    evernote_api = bot.get_evernote_api(user_id)
    all_notebooks = evernote_api.get_all_notebooks()
    buttons = []
    for notebook in all_notebooks:
        name = notebook['name']
        if name == user.evernote.notebook.name:
            name = f'> {name} <'
        buttons.append({'text': name})
    keyboard = {
        'keyboard': [[b] for b in buttons],
        'resize_keyboard': True,
        'one_time_keyboard': True,
    }
    bot.api.sendMessage(user.telegram.chat_id, 'Please, select notebook', json.dumps(keyboard))
    user.state = 'switch_notebook'
    bot.users.save(user.asdict())
Exemplo n.º 18
0
 def on_message(self, bot, message: Message):
     user_id = message.from_user.id
     user_data = self.users.get(user_id)
     if not user_data:
         raise EvernoteBotException(f"Unregistered user {user_id}. "
                                     "You've to send /start command to register")
     bot_user = BotUser(**user_data)
     if not bot_user.evernote or not bot_user.evernote.access.token:
         raise EvernoteBotException("You have to sign in to Evernote first. "
                                    "Send /start and press the button")
     if bot_user.state:
         self.handle_state(bot_user, message)
     else:
         self.handle_message(message)
Exemplo n.º 19
0
 def switch_mode(self, bot_user: BotUser, selected_mode_str: str):
     new_mode, new_mode_title = self._validate_mode(selected_mode_str)
     if bot_user.bot_mode == new_mode:
         text = f'The bot already in `{new_mode_title}` mode.'
         self.send_message(text)
         return
     if new_mode == 'one_note':
         self.switch_mode_one_note(bot_user)
     elif new_mode == 'multiple_notes':
         bot_user.evernote.shared_note_id = None
         bot_user.bot_mode = new_mode
         self.send_message(
             f'The bot has switched to `{new_mode_title}` mode.')
     raise EvernoteBotException(f'Unknown mode `{new_mode}`')
Exemplo n.º 20
0
 def switch_mode(self, bot_user: BotUser, selected_mode_str: str):
     new_mode, new_mode_title = self._validate_mode(selected_mode_str)
     chat_id = bot_user.telegram.chat_id
     if bot_user.bot_mode == new_mode:
         text = f"The bot already in '{new_mode_title}' mode."
         self.api.sendMessage(chat_id, text, json.dumps({"hide_keyboard": True}))
         return
     if new_mode == "one_note":
         self.switch_mode_one_note(bot_user)
         return
     # switching to 'multiple_notes' mode
     bot_user.evernote.shared_note_id = None
     bot_user.bot_mode = new_mode
     text = f"The bot has switched to '{new_mode_title}' mode."
     self.api.sendMessage(chat_id, text, json.dumps({"hide_keyboard": True}))
Exemplo n.º 21
0
 def _save_file_to_evernote(self, file_id, file_size, message: Message):
     max_size = 20 * 1024 * 1024 # telegram restriction. We can't download any file that has size more than 20Mb
     if file_size > max_size:
         raise EvernoteBotException('File too big. Telegram does not allow to the bot to download files over 20Mb.')
     filename, short_name = download_telegram_file(self.api, file_id, self.config["tmp_root"])
     user_data = self.users.get(message.from_user.id)
     user = BotUser(**user_data)
     self._check_evernote_quota(user, file_size)
     title = self.get_caption(message) or (message.text and message.text[:20]) or 'File'
     files = ({'path': filename, 'name': short_name},)
     text = ''
     telegram_link = message.get_telegram_link()
     if telegram_link:
         text = f'<div><p><a href="{telegram_link}">{telegram_link}</a></p><pre>{message.caption}</pre></div>'
     self.save_note(user, '', title=title, files=files, html=text)
Exemplo n.º 22
0
 def on_location(self, message: Message):
     latitude = message.location.latitude
     longitude = message.location.longitude
     maps_url = f"https://maps.google.com/maps?q={latitude},{longitude}"
     title = "Location"
     html = f"<a href='{maps_url}'>{maps_url}</a>"
     if message.venue:
         venue = message.venue
         title=venue.title or title
         address=venue.address
         html = f"{title}<br />{address}<br /><a href='{maps_url}'>{maps_url}</a>"
         foursquare_id = venue.foursquare_id
         if foursquare_id:
             url = f"https://foursquare.com/v/{foursquare_id}"
             html += f"<br /><a href='{url}'>{url}</a>"
     user_data = self.users.get(message.from_user.id)
     user = BotUser(**user_data)
     self.save_note(user, title=title, html=html)
Exemplo n.º 23
0
 def switch_mode_one_note(self, bot_user: BotUser):
     chat_id = bot_user.telegram.chat_id
     evernote_data = bot_user.evernote
     if evernote_data.access.permission == 'full':
         note = self.evernote(bot_user).create_note(
             evernote_data.notebook.guid,
             title='Telegram bot notes'
         )
         bot_user.bot_mode = 'one_note' # TODO: move up
         evernote_data.shared_note_id = note.guid
         note_url = self.evernote(bot_user).get_note_link(note.guid)
         text = f'Your notes will be saved to <a href="{note_url}">this note</a>'
         self.api.sendMessage(chat_id, text, json.dumps({'hide_keyboard': True}), parse_mode='Html')
     else:
         text = 'To enable "One note" mode you have to allow to the bot both reading and updating your notes'
         self.api.sendMessage(chat_id, text, json.dumps({'hide_keyboard': True}))
         message_text = 'Please, sign in and give the permissions to the bot.'
         bot_user.evernote.oauth = get_evernote_oauth_data(self, bot_user,
             message_text, access='full')
Exemplo n.º 24
0
 def on_location(self, message: Message):
     latitude = message.location.latitude
     longitude = message.location.longitude
     maps_url = f'https://maps.google.com/maps?q={latitude},{longitude}'
     title = 'Location'
     html = f'<a href="{maps_url}">{maps_url}</a>'
     if message.venue:
         venue = message.venue
         title = venue.title or title
         address = venue.address
         html = f'{title}<br />{address}<br /><a href="{maps_url}">{maps_url}</a>'
         foursquare_id = venue.foursquare_id
         if foursquare_id:
             url = f'https://foursquare.com/v/{foursquare_id}'
             html += f'<br /><a href="{url}">{url}</a>'
     user_data = self.users.get(message.from_user.id)
     user = BotUser(**user_data)
     title = self.get_caption(message) or title
     self.save_note(user, title=title, html=html)
Exemplo n.º 25
0
    def on_text(self, message: Message):
        def format_html(message: Message):
            if not message.entities:
                return message.text
            pointer = 0
            strings = []
            for entity in message.entities:
                strings.append(message.get_text(pointer, entity.offset))
                start, end = entity.offset, entity.offset + entity.length
                if start < pointer:
                    continue
                string = message.get_text(start, end)
                if entity.type == 'text_link':
                    url = entity.url
                    html = f'<a href="{url}">{string}</a>'
                elif entity.type == 'pre':
                    html = f'<pre>{string}</pre>'
                elif entity.type == 'bold':
                    html = f'<b>{string}</b>'
                elif entity.type == 'italic':
                    html = f'<i>{string}</i>'
                elif entity.type == 'underline':
                    html = f'<u>{string}</u>'
                elif entity.type == 'strikethrough':
                    html = f'<s>{string}</s>'
                else:
                    html = string
                strings.append(html)
                pointer = end
            strings.append(message.get_text(pointer))
            text = ''.join(strings)
            text = '<br />'.join(text.split('\n'))
            return text

        user_data = self.users.get(message.from_user.id)
        user = BotUser(**user_data)
        html = format_html(message)
        telegram_link = message.get_telegram_link()
        if telegram_link:
            html = f'<div><p><a href="{telegram_link}">{telegram_link}</a></p>{html}</div>'
        title = self.get_caption(message) or '[Telegram bot]'
        self.save_note(user, '', title=title, html=html)
Exemplo n.º 26
0
 def on_text(self, message: Message):
     user_data = self.users.get(message.from_user.id)
     user = BotUser(**user_data)
     text = message.text
     self.save_note(user, text, title=text[:20])