async def request_full_permissions(self, user): chat_id = user.telegram_chat_id text = 'To enable "One note" mode you should allow to bot to \ read and update your notes' res = self.send_message(chat_id, text, {'hide_keyboard': True}) await asyncio.wait([res]) text = 'Please tap on button below to give access to bot.' signin_button = { 'text': 'Waiting for Evernote...', 'url': self.url, } inline_keyboard = {'inline_keyboard': [[signin_button]]} message_future = self.send_message(chat_id, text, inline_keyboard) config_data = config['evernote']['full_access'] session = StartSession.get({'id': user.id}) oauth_data = await self.evernote.get_oauth_data(user.id, config_data, session.key) session.oauth_data = oauth_data signin_button['text'] = 'Allow read and update notes to bot' signin_button['url'] = oauth_data['oauth_url'] await asyncio.wait([message_future]) msg = message_future.result() asyncio.ensure_future( self.api.editMessageReplyMarkup( chat_id, msg['message_id'], json.dumps(inline_keyboard) ) ) session.save()
async def on_message_received(self, message: Message): user_id = message.user.id if '/start' in message.bot_commands: return if User.count({'id': user_id}) == 0: if StartSession.count({'id': user_id}) > 0: message_text = 'Please, sign in to Evernote account first: /start' error_text = 'User {0} not authorized in Evernote'.format(user_id) else: message_text = 'Who are you, stranger? Please, send /start command.' error_text = 'Unregistered user {0}'.format(user_id) self.send_message(message.chat.id, message_text) raise TelegramBotError(error_text) user = User.get({'id': user_id}) if not hasattr(user, 'evernote_access_token') or \ not user.evernote_access_token: self.send_message( user.telegram_chat_id, 'You should authorize first. Please, send /start command.' ) raise TelegramBotError( 'User {0} not authorized in Evernote'.format(user.id) ) user.last_request_time = datetime.datetime.now() user.save()
async def oauth_callback_full_access(request): logger = request.app.logger bot = request.app.bot hide_keyboard_markup = json.dumps({'hide_keyboard': True}) params = parse_qs(request.query_string) callback_key = params.get('key', [''])[0] session_key = params.get('session_key')[0] try: session = StartSession.get({'oauth_data.callback_key': callback_key}) user = User.get({'id': session.id}) except ModelNotFound as e: logger.error(e, exc_info=1) return web.HTTPForbidden() if session.key != session_key: text = "Session is expired. Please, send /start command to create new session" asyncio.ensure_future(bot.api.sendMessage(user.telegram_chat_id, text)) return web.HTTPFound(bot.url) try: if params.get('oauth_verifier'): oauth_verifier = params['oauth_verifier'][0] config = settings.EVERNOTE['full_access'] future = asyncio.ensure_future( bot.evernote_api.get_access_token( config['key'], config['secret'], session.oauth_data['oauth_token'], session.oauth_data['oauth_token_secret'], oauth_verifier)) future.add_done_callback( functools.partial(switch_to_one_note_mode, bot, user.id)) text = 'From now this bot in "One note" mode' asyncio.ensure_future( bot.api.sendMessage(user.telegram_chat_id, text, hide_keyboard_markup)) else: # User decline access logger.info('User declined full access =(') text = "We are sorry, but you deny read/update access😢" asyncio.ensure_future( bot.api.sendMessage(user.telegram_chat_id, text, hide_keyboard_markup)) except TokenRequestDenied as e: logger.error(e, exc_info=1) text = "We are sorry, but we have some problems with Evernote connection. Please try again later" asyncio.ensure_future( bot.api.sendMessage(user.telegram_chat_id, text, hide_keyboard_markup)) except Exception as e: logger.fatal(e, exc_info=1) text = "Oops. Unknown error. Our best specialist already working to fix it" asyncio.ensure_future( bot.api.sendMessage(user.telegram_chat_id, text, hide_keyboard_markup)) return web.HTTPFound(bot.url)
async def execute(self, message: Message): chat_id = message.chat.id user_id = message.user.id self.bot.track(message) config = settings.EVERNOTE['basic_access'] welcome_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.''' signin_button = { 'text': 'Waiting for Evernote...', 'url': self.bot.url, } inline_keyboard = {'inline_keyboard': [[signin_button]]} welcome_message_future = asyncio.ensure_future( self.bot.api.sendMessage(chat_id, welcome_text, json.dumps(inline_keyboard))) session_key = "".join([ random.choice(string.ascii_letters + string.digits) for i in range(32) ]) oauth_data = await self.bot.evernote_api.get_oauth_data( user_id, config['key'], config['secret'], config['oauth_callback'], session_key) session_data = { 'user': { 'username': message.user.username, 'first_name': message.user.first_name, 'last_name': message.user.last_name, }, 'chat_id': chat_id, } StartSession.create(id=user_id, key=session_key, data=session_data, oauth_data=oauth_data) signin_button['text'] = 'Sign in to Evernote' signin_button['url'] = oauth_data["oauth_url"] await asyncio.wait([welcome_message_future]) msg = welcome_message_future.result() asyncio.ensure_future( self.bot.api.editMessageReplyMarkup(chat_id, msg['message_id'], json.dumps(inline_keyboard)))
async def oauth_callback(request): logger = request.app.logger bot = request.app.bot config_data = config['evernote']['basic_access'] params = parse_qs(request.query_string) callback_key = params.get('key', [''])[0] session_key = params.get('session_key')[0] try: session = StartSession.get({'oauth_data.callback_key': callback_key}) except ModelNotFound as e: logger.error(e, exc_info=1) return web.HTTPForbidden() if not params.get('oauth_verifier'): logger.info('User declined access. No access token =(') bot.send_message(session.data['chat_id'], 'We are sorry, but you declined authorization 😢') return web.HTTPFound(bot.url) if session.key != session_key: text = 'Session is expired. \ Please, send /start command to create new session' bot.send_message(session.data['chat_id'], text) return web.HTTPFound(bot.url) user_data = session.data['user'] name = '{0} {1}'.format(user_data['first_name'], user_data['last_name']) user = User(id=session.id, name=name, username=user_data['username'], telegram_chat_id=session.data['chat_id'], mode='multiple_notes', places={}, settings={'evernote_access': 'basic'}) try: future = asyncio.ensure_future( bot.evernote.get_access_token(config_data, session.oauth_data, params['oauth_verifier'][0])) future.add_done_callback(functools.partial(set_access_token, bot, user)) except TokenRequestDenied as e: logger.error(e, exc_info=1) text = 'We are sorry, but we have some problems with Evernote \ connection. Please try again later' bot.send_message(user.telegram_chat_id, text) except Exception as e: logger.fatal(e, exc_info=1) bot.send_message(user.telegram_chat_id, 'Oops. Unknown error') text = 'Evernote account is connected.\n\ From now you can just send message and note be created.' bot.send_message(user.telegram_chat_id, text) user.save() return web.HTTPFound(bot.url)
async def test_start_command(testbot: EvernoteBot, text_update): update = text_update start_cmd = StartCommand(testbot) await start_cmd.execute(update.message) await asyncio.sleep(0.0001) sessions = StartSession.find() assert len(sessions) == 1 assert sessions[0].id == update.message.user.id assert sessions[0].oauth_data['oauth_url'] == 'test_oauth_url' assert testbot.api.sendMessage.call_count == 1 args = testbot.api.sendMessage.call_args[0] assert len(args) == 4 assert 'Welcome' in args[1] assert testbot.api.editMessageReplyMarkup.call_count == 1
async def oauth_callback_full_access(request): logger = request.app.logger bot = request.app.bot params = parse_qs(request.query_string) callback_key = params.get('key', [''])[0] session_key = params.get('session_key')[0] try: session = StartSession.get({'oauth_data.callback_key': callback_key}) user = User.get({'id': session.id}) except ModelNotFound as e: logger.error(e, exc_info=1) return web.HTTPForbidden() if not params.get('oauth_verifier'): logger.info('User declined full access =(') bot.send_message(user.telegram_chat_id, 'We are sorry, but you deny read/update access😢', {'hide_keyboard': True}) return web.HTTPFound(bot.url) if session.key != session_key: text = 'Session is expired. Please, send /start command to create \ new session' bot.send_message(user.telegram_chat_id, text) return web.HTTPFound(bot.url) try: oauth_verifier = params['oauth_verifier'][0] config_data = config['evernote']['full_access'] future = asyncio.ensure_future( bot.evernote.get_access_token(config_data, session.oauth_data, oauth_verifier)) future.add_done_callback( functools.partial(switch_to_one_note_mode, bot, user.id)) except TokenRequestDenied as e: logger.error(e, exc_info=1) bot.send_message( user.telegram_chat_id, 'We are sorry, but we have some problems with Evernote connection.\ Please try again later', {'hide_keyboard': True}) except Exception as e: logger.fatal(e, exc_info=1) bot.send_message(user.telegram_chat_id, 'Oops. Unknown error', {'hide_keyboard': True}) text = 'From now this bot in "One note" mode' bot.send_message(user.telegram_chat_id, text, {'hide_keyboard': True}) return web.HTTPFound(bot.url)
async def test_start_command(testbot: EvernoteBot, text_update: str): update = TelegramUpdate(json.loads(text_update)) start_cmd = StartCommand(testbot) await start_cmd.execute(update.message) await asyncio.sleep(0.0001) sessions = StartSession.find() assert len(sessions) == 1 assert sessions[0].id == update.message.user.id assert sessions[0].oauth_data['oauth_url'] == 'test_oauth_url' # TODO: # assert new_user.username == 'testuser' # assert new_user.first_name == 'test_first' # assert new_user.last_name == 'test_last' assert testbot.api.sendMessage.call_count == 1 args = testbot.api.sendMessage.call_args[0] assert len(args) == 3 assert 'Welcome' in args[1] assert testbot.api.editMessageReplyMarkup.call_count == 1
async def test_requre_full_permissions(user): StartSession.create(id=user.id, key='', data={}, oauth_data={}) config['evernote']['full_access'] = {} update_data = { 'update_id': 93710840, 'message': { 'date': datetime.datetime.now(), 'from': { 'username': user.username, 'id': user.id, }, 'chat': { 'id': user.id, 'type': 'private', 'username': user.username, }, 'message_id': 164, 'text': '/switch_mode', 'entities': [ { 'type': 'bot_command', 'offset': 0, 'length': 12 }, ], }, } bot = EvernoteBot('token', 'test_bot') bot.api.sendMessage = AsyncMock() await bot.handle_update(update_data) await asyncio.sleep(0.1) user = User.get({'id': user.id}) user.mode = 'multiple_notes' user.save() assert user.state == 'switch_mode' assert bot.api.sendMessage.call_count == 1 args = bot.api.sendMessage.call_args[0] assert args[1] == 'Please, select mode' bot.api.sendMessage.reset_mock() update_data = { 'update_id': 93710840, 'message': { 'date': datetime.datetime.now(), 'from': { 'username': user.username, 'id': user.id, }, 'chat': { 'id': user.id, 'type': 'private', 'username': user.username, }, 'message_id': 164, 'text': 'One note', }, } bot.api.sendMessage = AsyncMock(return_value={'message_id': 123}) bot.api.editMessageReplyMarkup = AsyncMock() bot.evernote.get_oauth_data = AsyncMock(return_value={'oauth_url': 'url'}) await bot.handle_update(update_data) await asyncio.sleep(0.1) session = StartSession.get({'id': user.id}) assert session.oauth_data['oauth_url'] == 'url' assert bot.evernote.get_oauth_data.call_count == 1 assert bot.api.editMessageReplyMarkup.call_count == 1 assert bot.api.sendMessage.call_count == 2
async def oauth_callback(request): logger = request.app.logger bot = request.app.bot config = settings.EVERNOTE['basic_access'] params = parse_qs(request.query_string) callback_key = params.get('key', [''])[0] session_key = params.get('session_key')[0] try: session = StartSession.get({'oauth_data.callback_key': callback_key}) user_data = session.data['user'] first_name = user_data['first_name'] last_name = user_data['last_name'] username = user_data['username'] user = User(id=session.id, name="{0} {1}".format(first_name, last_name), username=username, telegram_chat_id=session.data['chat_id'], mode='multiple_notes', places={}, settings={'evernote_access': 'basic'}) except ModelNotFound as e: logger.error(e, exc_info=1) return web.HTTPForbidden() if session.key != session_key: text = "Session is expired. Please, send /start command to create new session" asyncio.ensure_future(bot.api.sendMessage(user.telegram_chat_id, text)) return web.HTTPFound(bot.url) try: if params.get('oauth_verifier'): future = asyncio.ensure_future( bot.evernote_api.get_access_token( config['key'], config['secret'], session.oauth_data['oauth_token'], session.oauth_data['oauth_token_secret'], params['oauth_verifier'][0])) future.add_done_callback( functools.partial(set_access_token, bot, user)) text = 'Evernote account is connected.\nFrom now you can just send message and note be created.' asyncio.ensure_future( bot.api.sendMessage(user.telegram_chat_id, text)) user.save() else: # User decline access logger.info('User declined access. No access token =(') text = "We are sorry, but you declined authorization 😢" asyncio.ensure_future( bot.api.sendMessage(user.telegram_chat_id, text)) except TokenRequestDenied as e: logger.error(e, exc_info=1) text = "We are sorry, but we have some problems with Evernote connection. Please try again later" asyncio.ensure_future(bot.api.sendMessage(user.telegram_chat_id, text)) except Exception as e: logger.fatal(e, exc_info=1) text = "Oops. Unknown error. Our best specialist already working to fix it" if user: asyncio.ensure_future( bot.api.sendMessage(user.telegram_chat_id, text)) return web.HTTPFound(bot.url)
async def set_mode(self, user, mode): if mode.startswith('> ') and mode.endswith(' <'): mode = mode[2:-2] text_mode = '{0}'.format(mode) mode = mode.replace(' ', '_').lower() if mode == 'one_note': if user.settings.get('evernote_access', 'basic') == 'full': user.mode = mode reply = await self.api.sendMessage(user.telegram_chat_id, 'Please wait') notebook_guid = user.current_notebook['guid'] note_guid = await self.evernote_api.new_note( user.evernote_access_token, notebook_guid, text='', title='Note for Evernoterobot') user.places[user.current_notebook['guid']] = note_guid text = 'Bot switched to mode "{0}"'.format(text_mode) asyncio.ensure_future( self.api.editMessageText(user.telegram_chat_id, reply["message_id"], text)) text = 'New note was created in notebook "{0}"'.format( user.current_notebook['name']) asyncio.ensure_future( self.api.sendMessage(user.telegram_chat_id, text, json.dumps({'hide_keyboard': True}))) else: text = 'To enable "One note" mode you should allow to bot to read and update your notes' await self.api.sendMessage(user.telegram_chat_id, text, json.dumps({'hide_keyboard': True})) text = 'Please tap on button below to give access to bot.' signin_button = { 'text': 'Waiting for Evernote...', 'url': self.url, } inline_keyboard = {'inline_keyboard': [[signin_button]]} message_future = asyncio.ensure_future( self.api.sendMessage(user.telegram_chat_id, text, json.dumps(inline_keyboard))) config = settings.EVERNOTE['full_access'] session = StartSession.get({'id': user.id}) oauth_data = await self.evernote_api.get_oauth_data( user.id, config['key'], config['secret'], config['oauth_callback'], session.key) session.oauth_data = oauth_data signin_button['text'] = 'Allow read and update notes to bot' signin_button['url'] = oauth_data["oauth_url"] await asyncio.wait([message_future]) msg = message_future.result() asyncio.ensure_future( self.api.editMessageReplyMarkup( user.telegram_chat_id, msg['message_id'], json.dumps(inline_keyboard))) session.save() else: user.mode = mode asyncio.ensure_future( self.api.sendMessage( user.telegram_chat_id, 'From now this bot in mode "{0}"'.format(text_mode), reply_markup=json.dumps({'hide_keyboard': True}))) user.state = None user.save()