Compare commits

...

6 Commits

Author SHA1 Message Date
Tulir Asokan 1b719027e6 Bump version to 0.5.0rc2 2019-02-15 18:38:07 +02:00
Tulir Asokan d661f7b798 Bump minimum telethon-session-sqlalchemy to avoid SQL errors 2019-02-15 18:38:00 +02:00
Tulir Asokan e437869c13 Handle telegram chat upgrades in relaybot. Fixes #283 2019-02-15 18:35:31 +02:00
Tulir Asokan c979de9387 Fix creating base power levels for private chats. Fixes #282 2019-02-15 18:29:05 +02:00
Tulir Asokan be806949bf Fix handling thumbnails of documents. Fixes #281 2019-02-15 18:18:43 +02:00
Tulir Asokan 1c08725ade Add missing copyright headers and future-fstrings encodings 2019-02-15 17:59:04 +02:00
7 changed files with 88 additions and 37 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
__version__ = "0.5.0rc1"
__version__ = "0.5.0rc2"
__author__ = "Tulir Asokan <tulir@maunium.net>"
+7 -4
View File
@@ -23,7 +23,7 @@ from telethon.tl.types import (
ChannelParticipantAdmin, ChannelParticipantCreator, ChatForbidden, ChatParticipantAdmin,
ChatParticipantCreator, InputChannel, InputUser, MessageActionChatAddUser,
MessageActionChatDeleteUser, MessageEntityBotCommand, PeerChannel, PeerChat, TypePeer,
UpdateNewChannelMessage, UpdateNewMessage)
UpdateNewChannelMessage, UpdateNewMessage, MessageActionChatMigrateTo)
from telethon.tl.functions.messages import GetChatsRequest, GetFullChatRequest
from telethon.tl.functions.channels import GetChannelsRequest, GetParticipantRequest
from telethon.errors import ChannelInvalidError, ChannelPrivateError
@@ -238,7 +238,7 @@ class Bot(AbstractUser):
await self.handle_command_invite(portal, reply, mxid_input=mxid)
def handle_service_message(self, message: MessageService) -> None:
to_id = message.to_id
to_id = message.to_id # type: TelegramID
if isinstance(to_id, PeerChannel):
to_id = to_id.channel_id
chat_type = "channel"
@@ -250,9 +250,12 @@ class Bot(AbstractUser):
action = message.action
if isinstance(action, MessageActionChatAddUser) and self.tgid in action.users:
self.add_chat(TelegramID(to_id), chat_type)
self.add_chat(to_id, chat_type)
elif isinstance(action, MessageActionChatDeleteUser) and action.user_id == self.tgid:
self.remove_chat(TelegramID(to_id))
self.remove_chat(to_id)
elif isinstance(action, MessageActionChatMigrateTo):
self.remove_chat(to_id)
self.add_chat(TelegramID(action.channel_id), "channel")
async def update(self, update) -> bool:
if not isinstance(update, (UpdateNewMessage, UpdateNewChannelMessage)):
+16
View File
@@ -1,3 +1,19 @@
# -*- coding: future_fstrings -*-
# mautrix-telegram - A Matrix-Telegram puppeting bridge
# Copyright (C) 2018 Tulir Asokan
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from typing import Dict, Tuple
from mautrix_appservice import MatrixRequestError, IntentAPI
+16
View File
@@ -1,3 +1,19 @@
# -*- coding: future_fstrings -*-
# mautrix-telegram - A Matrix-Telegram puppeting bridge
# Copyright (C) 2018 Tulir Asokan
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from abc import abstractmethod
from sqlalchemy import Table
+43 -27
View File
@@ -418,24 +418,36 @@ class Portal:
def _get_base_power_levels(self, levels: dict = None, entity: TypeChat = None) -> dict:
levels = levels or {}
levels["ban"] = 99
levels["kick"] = 50
levels["invite"] = 50 if entity.default_banned_rights.invite_users else 0
if "events" not in levels:
levels["events"] = {}
levels["events"]["m.room.name"] = 50 if entity.default_banned_rights.change_info else 0
levels["events"]["m.room.avatar"] = 50 if entity.default_banned_rights.change_info else 0
levels["events"]["m.room.topic"] = 50 if entity.default_banned_rights.change_info else 0
levels["events"][
"m.room.pinned_events"] = 50 if entity.default_banned_rights.pin_messages else 0
levels["events"]["m.sticker"] = 50 if entity.default_banned_rights.send_stickers else 0
levels["events"]["m.room.power_levels"] = 75
levels["events"]["m.room.history_visibility"] = 75
levels["state_default"] = 50
levels["users_default"] = 0
levels["events_default"] = (50 if (self.peer_type == "channel" and not entity.megagroup
or entity.default_banned_rights.send_messages)
else 0)
if self.peer_type == "user":
levels["ban"] = 100
levels["kick"] = 100
levels["invite"] = 100
levels.setdefault("events", {})
levels["events"]["m.room.name"] = 0
levels["events"]["m.room.avatar"] = 0
levels["events"]["m.room.topic"] = 0
levels["state_default"] = 0
levels["users_default"] = 0
levels["events_default"] = 0
else:
dbr = entity.default_banned_rights
levels["ban"] = 99
levels["kick"] = 50
levels["invite"] = 50 if dbr.invite_users else 0
levels.setdefault("events", {})
levels["events"]["m.room.name"] = 50 if dbr.change_info else 0
levels["events"]["m.room.avatar"] = 50 if dbr.change_info else 0
levels["events"]["m.room.topic"] = 50 if dbr.change_info else 0
levels["events"][
"m.room.pinned_events"] = 50 if dbr.pin_messages else 0
levels["events"]["m.sticker"] = 50 if dbr.send_stickers else 0
levels["events"]["m.room.power_levels"] = 75
levels["events"]["m.room.history_visibility"] = 75
levels["state_default"] = 50
levels["users_default"] = 0
levels["events_default"] = (50 if (self.peer_type == "channel" and not entity.megagroup
or entity.default_banned_rights.send_messages)
else 0)
if "users" not in levels:
levels["users"] = {
self.main_intent.mxid: 100
@@ -598,8 +610,8 @@ class Portal:
return False
@staticmethod
def _get_largest_photo_size(photo: Photo) -> TypePhotoSize:
return max(photo.sizes, key=(lambda photo2: (
def _get_largest_photo_size(photo: Union[Photo, List[TypePhotoSize]]) -> TypePhotoSize:
return max(photo.sizes if isinstance(photo, Photo) else photo, key=(lambda photo2: (
len(photo2.bytes) if not isinstance(photo2, PhotoSize) else photo2.size)))
async def remove_avatar(self, _: 'AbstractUser', save: bool = False) -> None:
@@ -1352,8 +1364,8 @@ class Portal:
return attrs
@staticmethod
def _parse_telegram_document_meta(evt: Message, file: DBTelegramFile, attrs: Dict
) -> Tuple[Dict, str]:
def _parse_telegram_document_meta(evt: Message, file: DBTelegramFile, attrs: Dict,
thumb: TypePhotoSize) -> Tuple[Dict, str]:
document = evt.media.document
name = evt.message or attrs["name"]
if attrs["is_sticker"]:
@@ -1381,8 +1393,8 @@ class Portal:
info["thumbnail_url"] = file.thumbnail.mxc
info["thumbnail_info"] = {
"mimetype": file.thumbnail.mime_type,
"h": file.thumbnail.height or document.thumb.h,
"w": file.thumbnail.width or document.thumb.w,
"h": file.thumbnail.height or thumb.h,
"w": file.thumbnail.width or thumb.w,
"size": file.thumbnail.size,
}
@@ -1393,12 +1405,16 @@ class Portal:
document = evt.media.document
attrs = self._parse_telegram_document_attributes(document.attributes)
file = await util.transfer_file_to_matrix(source.client, intent, document,
document.thumb, is_sticker=attrs["is_sticker"])
thumb = self._get_largest_photo_size(document.thumbs)
if not isinstance(thumb, (PhotoSize, PhotoCachedSize)):
self.log.debug(f"Unsupported thumbnail type {type(thumb)}")
thumb = None
file = await util.transfer_file_to_matrix(source.client, intent, document, thumb,
is_sticker=attrs["is_sticker"])
if not file:
return None
info, name = self._parse_telegram_document_meta(evt, file, attrs)
info, name = self._parse_telegram_document_meta(evt, file, attrs, thumb)
await intent.set_typing(self.mxid, is_typing=False)
+4 -4
View File
@@ -23,8 +23,8 @@ import asyncio
import magic
from sqlalchemy.exc import IntegrityError, InvalidRequestError
from telethon.tl.types import (Document, FileLocation, InputFileLocation,
InputDocumentFileLocation, PhotoSize, PhotoCachedSize)
from telethon.tl.types import (Document, FileLocation, InputFileLocation, InputDocumentFileLocation,
TypePhotoSize, PhotoSize, PhotoCachedSize)
from telethon.errors import (AuthBytesInvalidError, AuthKeyInvalidError, LocationInvalidError,
SecurityError)
from mautrix_appservice import IntentAPI
@@ -149,7 +149,7 @@ transfer_locks = {} # type: Dict[str, asyncio.Lock]
async def transfer_file_to_matrix(client: MautrixTelegramClient, intent: IntentAPI,
location: TypeLocation, thumbnail: Optional[TypeLocation] = None,
location: TypeLocation, thumbnail: Optional[Union[TypeLocation, TypePhotoSize]] = None,
is_sticker: bool = False) -> Optional[DBTelegramFile]:
location_id = _location_to_id(location)
if not location_id:
@@ -171,7 +171,7 @@ async def transfer_file_to_matrix(client: MautrixTelegramClient, intent: IntentA
async def _unlocked_transfer_file_to_matrix(client: MautrixTelegramClient, intent: IntentAPI,
loc_id: str, location: TypeLocation,
thumbnail: Optional[TypeLocation],
thumbnail: Optional[Union[TypeLocation, TypePhotoSize]],
is_sticker: bool) -> Optional[DBTelegramFile]:
db_file = DBTelegramFile.get(loc_id)
if db_file:
+1 -1
View File
@@ -40,7 +40,7 @@ setuptools.setup(
"future-fstrings>=0.4.2",
"python-magic>=0.4.15,<0.5",
"telethon>=1.5.5,<1.6",
"telethon-session-sqlalchemy>=0.2.7,<0.3",
"telethon-session-sqlalchemy>=0.2.8,<0.3",
],
extras_require=extras,