async def gmail_pubsub_push(request: web.Request): """ Handle webhooks from gmail (google pub/sub subscribition) """ MAX_SIZE = 26214400 if request.content_length > MAX_SIZE: raise web.HTTPRequestEntityTooLarge(MAX_SIZE, request.content_length) request_data = await request.json() logging.info(str(request_data)) if request_data.get('message'): notification_data = request_data['message']['data'] update = json.loads( urlsafe_b64decode(notification_data).decode('utf-8')) email: str = update["emailAddress"] new_history_id: int = int(update["historyId"]) creds = tuple(await psqldb.get_gmail_creds(email=email)) user_creds = gmail_API.make_user_creds(*creds) history_id = await psqldb.update_watch_history( email=email, history_id=new_history_id) if history_id: # TODO: Catch 404 and make a full sync in that case # https://developers.google.com/gmail/api/guides/sync#full_synchronization hist = await gmail_API.read_history(user_creds=user_creds, email=email, history_id=str(history_id)) if hist.get("history"): creds = tuple(await psqldb.get_gmail_creds(email=email)) user_creds = gmail_API.make_user_creds(*creds) watched_chats_records = tuple( await psqldb.get_watched_chats(email=email)) for history_record in hist["history"]: for message_record in history_record["messages"]: message_id = message_record["id"] msg = await gmail_API.get_message_full( user_creds=user_creds, message_id=message_id, ) # ON new messages -- send it to all the watched chats linked with this email for chat_id_record in watched_chats_records: for text in msg['text_list']: await dp.bot.send_message( chat_id_record["chat_id"], text) for file in msg['attachments']: await dp.bot.send_document( chat_id_record["chat_id"], types.input_file.InputFile( BytesIO(file['file']), filename=file['filename'])) else: logging.info(f"Problems with updating history_id in {email}") return web.Response(text='OK')
async def update_one_watched_email(email): logging.info("Updating last_watch: " + email) creds = tuple(await psqldb.get_gmail_creds(email=email)) user_creds = gmail_API.make_user_creds(*creds) watch_response = await gmail_API.start_watch(user_creds=user_creds, email=email) if watch_response: await psqldb.watch_email(email=email, history_id=int(watch_response["historyId"]))
async def remove(message: types.Message, state: FSMContext): email = message.text.strip() chat_id = message.chat.id if not match(r'^[\w\.-]+@gmail\.com$', email): logging.info(f"Mail {email} was rejected") await message.answer('Невідомий формат пошти') else: await psqldb.remove_watched_chat_emails(email=email, chat_id=chat_id) await message.answer(f'Сповіщення від пошти {email} відключені') watched_chats = tuple(await psqldb.get_watched_chats(email=email)) if not watched_chats: creds = tuple(await psqldb.get_gmail_creds(email=email)) user_creds = gmail_API.make_user_creds(*creds) await gmail_API.stop_watch(user_creds=user_creds, email=email) await psqldb.remove_watched_email(email=email) await state.finish()
async def add(message: types.Message, state: FSMContext): email = message.text.strip() chat_id = message.chat.id if not match(r'^[\w\.-]+@gmail\.com$', email): logging.info(f"Mail {email} was rejected") await message.answer('Невідомий формат пошти') else: # TODO: check if that email is attached to the chat match_email_chat = await psqldb.email_in_chat(email=email, chat_id=chat_id) if not match_email_chat: await message.answer(f'Пошта {email} не приєднана до чату') else: # link email to chat to send emails in the future await psqldb.add_watched_chat_emails(email=email, chat_id=chat_id) # then only watch email if it not already watched is_email_watched = await psqldb.email_watched(email=email) # if email already watched -- thats all, just add to the chat, not watch if not is_email_watched: creds = tuple(await psqldb.get_gmail_creds(email=email)) user_creds = gmail_API.make_user_creds(*creds) watch_response = await gmail_API.start_watch( user_creds=user_creds, email=email) # watch response example # {'historyId': '1336627', 'expiration': '1612395124174'} logging.info(str(watch_response)) if watch_response: await psqldb.watch_email(email=email, history_id=int( watch_response["historyId"])) await message.answer( f'Сповіщення від пошти {email} додані до чату') else: await message.answer( f'Не вдалося додати сповіщення від пошти {email}') else: await message.answer( f'Сповіщення від пошти {email} прикріплені до чату') await state.finish()
async def last_email(message: types.Message): """ Handle command such as `/last [email protected]` Send user text and attachment from last email from that email """ # a lot of bugs here args = message.get_args() # yeah it need at least some verification email = args creds = tuple(await psqldb.get_gmail_creds(email=email)) user_creds = gmail_API.make_user_creds(*creds) messages = await gmail_API.messages_list( user_creds=user_creds, messages_num=1, ) messages = [gmail_API.get_text_attachments(msg) for msg in messages] for msg in messages: for text in msg['text_list']: await message.answer(text) for file in msg['attachments']: await message.answer_document( types.input_file.InputFile(BytesIO(file['file']), filename=file['filename'])) del messages