Skip to content
This repository has been archived by the owner on Mar 11, 2020. It is now read-only.

Commit

Permalink
IO attachments (#40)
Browse files Browse the repository at this point in the history
- Move gate API clients to their own module.
- Add function to download media.
- Modify gate API clients to work with IO instead of link to media.
  • Loading branch information
vladimirshkoda authored Feb 25, 2019
1 parent 6f83ad9 commit db8f8b8
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 26 deletions.
2 changes: 1 addition & 1 deletion postpost/api/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
from celery.schedules import crontab
from celery.task import periodic_task

from api import telegram, vkontakte
from api.models import PlatformPost
from gates import telegram, vkontakte

logger = logging.getLogger(__name__)

Expand Down
Empty file added postpost/gates/__init__.py
Empty file.
15 changes: 15 additions & 0 deletions postpost/gates/download_media.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from io import BytesIO
from typing import IO

import requests


def download_media(url: str) -> IO[bytes]:
"""
Downloads media by the given link and returns IO with it.
"""
response = requests.get(url, allow_redirects=True)
response.raise_for_status()
reader = BytesIO(response.content)
reader.name = url.split('/')[-1]
return reader
49 changes: 34 additions & 15 deletions postpost/api/telegram.py → postpost/gates/telegram.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import IO, Dict, Union

import requests

from api.models import PlatformPost
Expand All @@ -8,9 +10,9 @@ def send_post_to_telegram_chat(token: str, chat_id: str, post: PlatformPost) ->
"""
Sends post to telegram chat.
"""
tg = TgAPI(token=token, chat_id=chat_id)
tg = TgAPI(token=token)
# TODO: Add media according to PlatformPost changes
return tg.send_message(text=post.text_for_posting)
return tg.send_message(chat_id=chat_id, text=post.text_for_posting)


class TgAPI(object):
Expand All @@ -20,15 +22,15 @@ class TgAPI(object):
Its purpose it to share API token and chat id among the methods.
"""

def __init__(self, token: str, chat_id: str):
def __init__(self, token: str):
"""
Init client.
"""
self._url = 'https://api.telegram.org/bot{0}/'.format(token)
self._chat_id = chat_id

def send_message(
self,
chat_id: str,
text: str,
disable_notification: bool = False,
disable_web_page_preview: bool = True,
Expand All @@ -38,37 +40,54 @@ def send_message(
"""
return self._request(
'sendMessage',
chat_id=self._chat_id,
chat_id=chat_id,
text=text,
parse_mode='Markdown',
disable_notification=disable_notification,
disable_web_page_preview=disable_web_page_preview,
)

def send_photo(self, photo: str, disable_notification: bool = False) -> JSON:
def send_photo(
self,
chat_id: str,
photo: IO[bytes],
disable_notification: bool = False,
) -> JSON:
"""
Sends the photo to the chat.
"""
return self._request(
'sendPhoto',
chat_id=self._chat_id,
photo=photo,
chat_id=chat_id,
media={'photo': photo},
disable_notification=disable_notification,
)

def send_animation(self, animation: str, disable_notification: bool = False) -> JSON:
def send_animation(
self,
chat_id: str,
animation: IO[bytes],
disable_notification: bool = False,
) -> JSON:
"""
Sends the animation to the chat.
"""
return self._request(
'sendAnimation',
chat_id=self._chat_id,
animation=animation,
chat_id=chat_id,
media={'animation': animation},
disable_notification=disable_notification,
)

def _request(self, method_name: str, **kwargs) -> JSON:
response = requests.post(self._url + method_name, json=kwargs)
def _request(
self,
method_name: str,
media: Union[Dict[str, IO[bytes]], None] = None,
**kwargs,
) -> JSON:
"""
Sends request to the Telegram API method with the given payload.
"""
response = requests.post(self._url + method_name, data=kwargs, files=media)
response.raise_for_status()
json: JSON = response.json()
return json
return response.json()
26 changes: 16 additions & 10 deletions postpost/api/vkontakte.py → postpost/gates/vkontakte.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,11 @@ def upload_doc(self, doc: IO[bytes]) -> str:
"""
upload_url = self._request('docs.getWallUploadServer')['upload_url']

response = requests.post(upload_url, files={'file': doc})
if response.status_code != requests.codes.ok or 'error' in response.json():
raise VkAPIError(upload_url, {'file': doc}, response.content)
uploaded_doc = self._upload_media(upload_url, doc)

saved_doc = self._request(
'docs.save',
{'file': response.json()['file']},
{'file': uploaded_doc['file']},
)['doc']
return 'doc{0}_{1}'.format(saved_doc['owner_id'], saved_doc['id'])

Expand All @@ -110,10 +108,7 @@ def upload_photo(self, group_id: int, photo: IO[bytes]) -> str:
{'group_id': group_id},
)['upload_url']

response = requests.post(upload_url, files={'file': photo})
if response.status_code != requests.codes.ok or 'error' in response.json():
raise VkAPIError(upload_url, {'file': photo}, response.content)
uploaded_photo = response.json()
uploaded_photo = self._upload_media(upload_url, photo)

saved_photo = self._request(
'photos.saveWallPhoto', {
Expand All @@ -126,6 +121,9 @@ def upload_photo(self, group_id: int, photo: IO[bytes]) -> str:
return 'photo{0}_{1}'.format(saved_photo['owner_id'], saved_photo['id'])

def _request(self, method: str, payload: JSON = None) -> JSON:
"""
Sends request to the VK API method with the given payload.
"""
if payload is None:
payload = {}
payload.update({
Expand All @@ -135,5 +133,13 @@ def _request(self, method: str, payload: JSON = None) -> JSON:
response = requests.post(self._url + method, data=payload)
if response.status_code != requests.codes.ok or 'error' in response.json():
raise VkAPIError(method, payload, response.content)
json: JSON = response.json()['response']
return json
return response.json()['response']

def _upload_media(self, upload_url: str, media: IO[bytes]) -> JSON:
"""
Upload media to the VK server.
"""
response = requests.post(upload_url, files={'file': media})
if response.status_code != requests.codes.ok or 'error' in response.json():
raise VkAPIError(upload_url, {'file': media.name}, response.content)
return response.json()

0 comments on commit db8f8b8

Please sign in to comment.