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(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 list_users(request): page = request.GET.get('page', 0) page_size = 50 total_cnt = User.count() num_pages = total_cnt / page_size + 1 users = [ x for x in User.find({}, skip=page * page_size, limit=page_size, sort=[('last_request_time', -1)]) ] return aiohttp_jinja2.render_template('users.html', request, { 'users': users, 'num_pages': num_pages, })
async def on_voice(self, message: Message): user = User.get({'id': message.user.id}) voice = message.voice DownloadTask.create(user_id=user.id, file_id=voice.file_id, file_size=voice.file_size, completed=False) self.accept_request(user, 'voice', message)
async def on_document(self, message: Message): user = User.get({'id': message.user.id}) self.accept_request(user, 'document', message) document = message.document DownloadTask.create(user_id=user.id, file_id=document.file_id, file_size=document.file_size, completed=False)
async def on_video(self, message: Message): user = User.get({'id': message.user.id}) self.accept_request(user, 'video', message) video = message.video DownloadTask.create(user_id=user.id, file_id=video.file_id, file_size=video.file_size, completed=False)
async def on_photo(self, message: Message): user = User.get({'id': message.user.id}) self.accept_request(user, 'photo', message) files = sorted(message.photos, key=lambda x: x.file_size, reverse=True) DownloadTask.create(user_id=user.id, file_id=files[0].file_id, file_size=files[0].file_size, completed=False)
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 on_text(self, message: Message): user = User.get({'id': message.user.id}) text = message.text if user.state == 'select_notebook': if text.startswith('> ') and text.endswith(' <'): text = text[2:-2] await self.set_current_notebook(user, text) elif user.state == 'switch_mode': await self.set_mode(user, text) else: self.accept_request(user, 'text', message)
def switch_to_one_note_mode(bot, user_id, access_token_future): user = User.get({'id': user_id}) access_token = access_token_future.result() user.evernote_access_token = access_token user.settings['evernote_access'] = 'full' user.mode = 'one_note' user.save() future = asyncio.ensure_future( bot.evernote.create_note(user.evernote_access_token, 'Note for Evernoterobot', '', user.current_notebook['guid'])) future.add_done_callback(functools.partial(save_default_note_guid, user_id))
async def list_users(request): page = request.GET.get('page', 0) page_size = 50 total_cnt = User.count() now = datetime.datetime.now() week_ago = now - datetime.timedelta(days=7) month_ago = now - datetime.timedelta(days=30) weekly_active = User.count({'last_request_time': {'$gte': week_ago}}) monthly_active = User.count({'last_request_time': {'$gte': month_ago}}) num_pages = total_cnt / page_size + 1 all_users = User.find({}, skip=page*page_size, limit=page_size, sort=[('last_request_time', -1)]) users = [x for x in all_users] return aiohttp_jinja2.render_template( 'users.html', request, { 'users': users, 'num_pages': num_pages, 'total': total_cnt, 'monthly_active': monthly_active, 'weekly_active': weekly_active, } )
def user(): note_guid = generate_string(32) notebook_guid = generate_string(32) user = User.create(id=random.randint(1, 100), name=generate_string(5), username=generate_string(5), telegram_chat_id=random.randint(1, 100), mode='one_note', evernote_access_token='token', current_notebook={ 'guid': notebook_guid, 'name': 'test_notebook' }, places={notebook_guid: note_guid}) return user
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 execute(self, message: Message): user = User.get({'id': message.user.id}) buttons = [] for mode in ['one_note', 'multiple_notes']: if user.mode == mode: name = "> %s <" % mode.capitalize().replace('_', ' ') else: name = mode.capitalize().replace('_', ' ') buttons.append({'text': name}) self.bot.send_message( user.telegram_chat_id, 'Please, select mode', { 'keyboard': [[b] for b in buttons], 'resize_keyboard': True, 'one_time_keyboard': True, }) user.state = 'switch_mode' user.save()
async def async_run(self): try: while True: updates_by_user = self.fetch_updates() if not updates_by_user: await asyncio.sleep(0.1) continue for user_id, updates in updates_by_user.items(): try: user = User.get({'id': user_id}) asyncio.ensure_future( self.process_user_updates(user, updates)) except Exception as e: self.logger.error( "Can't process updates for user {0}\n{1}".format( user_id, e), exc_info=1) except Exception: self.logger.fatal('Dealer DOWN!!!', exc_info=1)
async def execute(self, message: Message): user = User.get({'id': message.user.id}) notebooks = await self.bot.evernote.list_notebooks( user.evernote_access_token) buttons = [] for notebook in notebooks: if notebook['guid'] == user.current_notebook['guid']: name = '> {} <'.format(notebook['name']) else: name = notebook['name'] buttons.append({'text': name}) self.bot.send_message( user.telegram_chat_id, 'Please, select notebook', { 'keyboard': [[b] for b in buttons], 'resize_keyboard': True, 'one_time_keyboard': True, }) user.state = 'select_notebook' user.save()
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 on_location(self, message: Message): user = User.get({'id': message.user.id}) await self.handle_request(user, 'location', message)
async def on_voice(self, message: Message): user = User.get({'id': message.user.id}) await self.handle_request(user, 'voice', message)
async def on_document(self, message: Message): user = User.get({'id': message.user.id}) await self.handle_request(user, 'document', message)
async def on_photo(self, message: Message): user = User.get({'id': message.user.id}) await self.handle_request(user, 'photo', message)
async def on_location(self, message: Message): user = User.get({'id': message.user.id}) self.accept_request(user, 'location', message)
async def handle_callback_query(self, query: CallbackQuery): data = json.loads(query.data) if data['cmd'] == 'set_nb': user = User.get({'id': query.user.id}) await self.set_current_notebook(user, notebook_guid=data['nb'])
def save_default_note_guid(user_id, note_guid_future): user = User.get({'id': user_id}) note_guid = note_guid_future.result() user.places[user.current_notebook['guid']] = note_guid user.save()
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 test_switch_notebook(user): 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': '/notebook', 'entities': [ { 'type': 'bot_command', 'offset': 0, 'length': 9 }, ], }, } bot = EvernoteBot('token', 'test_bot') Notebook = namedtuple('Notebook', ['guid', 'name']) notebooks = [ Notebook(user.current_notebook['guid'], user.current_notebook['name']), Notebook(guid='123', name='test_nb') ] bot.evernote.api.list_notebooks = AsyncMock(return_value=notebooks) bot.evernote.create_note = AsyncMock() bot.evernote.get_note_link = AsyncMock() bot.api.editMessageText = AsyncMock() bot.api.sendMessage = AsyncMock() await bot.handle_update(update_data) user = User.get({'id': user.id}) user.mode = 'multiple_notes' user.save() assert user.state == 'select_notebook' await asyncio.sleep(0.1) assert bot.api.sendMessage.call_args[0][1] == 'Please, select notebook' markup = json.loads(bot.api.sendMessage.call_args[0][2]) assert markup['one_time_keyboard'] assert markup['keyboard'] nb = markup['keyboard'][0][0] assert nb['text'] == '> {0} <'.format(user.current_notebook['name']) bot.evernote.api.list_notebooks = AsyncMock(return_value=notebooks) bot.evernote.create_note.reset_mock() 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': 'test_nb', }, } await bot.handle_update(update_data) await asyncio.sleep(0.1) user = User.get({'id': user.id}) assert user.current_notebook['guid'] == '123' assert bot.evernote.api.list_notebooks.call_count == 1 assert bot.api.sendMessage.call_count == 1 assert bot.api.sendMessage.call_args[0][1].startswith( 'From now your current notebook is: test_nb' )