Merge branch 'master' into independent-login

This commit is contained in:
Tulir Asokan
2018-02-20 21:48:05 +02:00
33 changed files with 1576 additions and 813 deletions
+19 -3
View File
@@ -19,6 +19,7 @@ import asyncio
from telethon.errors import *
from . import command_handler
from .. import puppet as pu
@command_handler(needs_auth=False)
@@ -32,6 +33,18 @@ async def ping(evt):
return await evt.reply("You're not logged in.")
@command_handler()
async def ping_bot(evt):
if not evt.tgbot:
return await evt.reply("Telegram message relay bot not configured.")
bot_info = await evt.tgbot.client.get_me()
mxid = pu.Puppet.get_mxid_from_id(bot_info.id)
displayname = bot_info.first_name
return await evt.reply("Telegram message relay bot is active: "
f"[{displayname}](https://matrix.to/#/{mxid}) (ID {bot_info.id})\n\n"
"To use the bot, simply invite it to a portal room.")
@command_handler(needs_auth=False, management_only=True)
def register(evt):
return evt.reply("Not yet implemented.")
@@ -45,6 +58,7 @@ async def login(evt):
return await evt.reply("**Usage:** `$cmdprefix+sp login <phone number>`")
phone_number = evt.args[0]
try:
await evt.sender.ensure_started(even_if_no_session=True)
await evt.sender.client.sign_in(phone_number)
evt.sender.command_status = {
"next": enter_code,
@@ -60,6 +74,9 @@ async def login(evt):
"The ban is usually applied for around a day.")
except PhoneNumberBannedError:
return await evt.reply("Your phone number has been banned from Telegram.")
except PhoneNumberUnoccupiedError:
return await evt.reply("That phone number has not been registered. "
"Please register with `$cmdprefix+sp register <phone>`.")
except Exception:
evt.log.exception("Error requesting phone code")
return await evt.reply("Unhandled exception while requesting code. "
@@ -72,13 +89,11 @@ async def enter_code(evt):
return await evt.reply("**Usage:** `$cmdprefix+sp enter-code <code>`")
try:
await evt.sender.ensure_started(even_if_no_session=True)
user = await evt.sender.client.sign_in(code=evt.args[0])
asyncio.ensure_future(evt.sender.post_login(user), loop=evt.loop)
evt.sender.command_status = None
return await evt.reply(f"Successfully logged in as @{user.username}")
except PhoneNumberUnoccupiedError:
return await evt.reply("That phone number has not been registered. "
"Please register with `$cmdprefix+sp register <phone>`.")
except PhoneCodeExpiredError:
return await evt.reply(
"Phone code expired. Try again with `$cmdprefix+sp login <phone>`.")
@@ -103,6 +118,7 @@ async def enter_password(evt):
return await evt.reply("**Usage:** `$cmdprefix+sp enter-password <password>`")
try:
await evt.sender.ensure_started(even_if_no_session=True)
user = await evt.sender.client.sign_in(password=evt.args[0])
asyncio.ensure_future(evt.sender.post_login(user), loop=evt.loop)
evt.sender.command_status = None
+7 -7
View File
@@ -52,7 +52,7 @@ async def _find_rooms(intent):
return management_rooms, unidentified_rooms, portals, empty_portals
@command_handler(needs_admin=True, name="clean-rooms")
@command_handler(needs_admin=True, needs_auth=False, name="clean-rooms")
async def clean_rooms(evt):
if not evt.is_management:
return await evt.reply("`clean-rooms` is a particularly spammy command. Please don't "
@@ -66,7 +66,7 @@ async def clean_rooms(evt):
or ["No management rooms found."])
reply.append("#### Active portal rooms (A)")
reply += ([f"{n+1}. [P{n+1}](https://matrix.to/#/{portal.mxid}) "
+ f"(to Telegram chat \"{portal.title}\")"
f"(to Telegram chat \"{portal.title}\")"
for n, portal in enumerate(portals)]
or ["No active portal rooms found."])
reply.append("#### Unidentified rooms (U)")
@@ -75,7 +75,7 @@ async def clean_rooms(evt):
or ["No unidentified rooms found."])
reply.append("#### Inactive portal rooms (I)")
reply += ([f"{n}. [E{n}](https://matrix.to/#/{portal.mxid}) "
+ f"(to Telegram chat \"{portal.title}\")"
f"(to Telegram chat \"{portal.title}\")"
for n, portal in enumerate(empty_portals)]
or ["No inactive portal rooms found."])
@@ -141,21 +141,21 @@ async def set_rooms_to_clean(evt, management_rooms, unidentified_rooms, portals,
"**Usage:** `$cmdprefix+sp clean-groups <_M|A|U|I_><range>")
else:
return await evt.reply(f"Unknown room cleaning action `{command}`. "
+ "Use `$cmdprefix+sp cancel` to cancel room "
+ "cleaning.")
"Use `$cmdprefix+sp cancel` to cancel room "
"cleaning.")
evt.sender.command_status = {
"next": lambda confirm: execute_room_cleanup(confirm, rooms_to_clean),
"action": "Room cleaning",
}
await evt.reply(f"To confirm cleaning up {len(rooms_to_clean)} rooms, type"
+ "`$cmdprefix+sp confirm-clean`.")
"`$cmdprefix+sp confirm-clean`.")
async def execute_room_cleanup(evt, rooms_to_clean):
if len(evt.args) > 0 and evt.args[0] == "confirm-clean":
await evt.reply(f"Cleaning {len(rooms_to_clean)} rooms. "
+ "This might take a while.")
"This might take a while.")
cleaned = 0
for room in rooms_to_clean:
if isinstance(room, po.Portal):
+6 -4
View File
@@ -29,7 +29,7 @@ def command_handler(needs_auth=True, management_only=False, needs_admin=False, n
def wrapper(evt):
if management_only and not evt.is_management:
return evt.reply(f"`{evt.command}` is a restricted command:"
+ "you may only run it in management rooms.")
"you may only run it in management rooms.")
elif needs_auth and not evt.sender.logged_in:
return evt.reply("This command requires you to be logged in.")
elif needs_admin and not evt.sender.is_admin:
@@ -47,6 +47,8 @@ class CommandEvent:
self.az = handler.az
self.log = handler.log
self.loop = handler.loop
self.tgbot = handler.tgbot
self.config = handler.config
self.command_prefix = handler.command_prefix
self.room_id = room
self.sender = sender
@@ -71,7 +73,7 @@ class CommandHandler:
log = logging.getLogger("mau.commands")
def __init__(self, context):
self.az, self.db, self.config, self.loop = context
self.az, self.db, self.config, self.loop, self.tgbot = context
self.command_prefix = self.config["bridge.command_prefix"]
# region Utility functions for handling commands
@@ -94,6 +96,6 @@ class CommandHandler:
except FloodWaitError as e:
return evt.reply(f"Flood error: Please wait {format_duration(e.seconds)}")
except Exception:
self.log.exception(f"Fatal error handling command "
+ f"{evt.command} {' '.join(args)} from {sender.mxid}")
self.log.exception("Fatal error handling command "
f"{evt.command} {' '.join(args)} from {sender.mxid}")
return evt.reply("Fatal error while handling command. Check logs for more details.")
+1
View File
@@ -65,6 +65,7 @@ def help(evt):
`channel` (defaults to `group`).
#### Portal management
**ping-bot** - Get info of the message relay Telegram bot.
**upgrade** - Upgrade a normal Telegram group to a supergroup.
**invite-link** - Get a Telegram invite link to the current chat.
**delete-portal** - Forget the current portal room. Only works for group chats; to delete
+15 -14
View File
@@ -51,7 +51,7 @@ async def search(evt):
else:
reply += ["**Results in contacts:**", ""]
reply += [(f"* [{puppet.displayname}](https://matrix.to/#/{puppet.mxid}): "
+ f"{puppet.id} ({similarity}% match)")
f"{puppet.id} ({similarity}% match)")
for puppet, similarity in results]
# TODO somehow show remote channel results when joining by alias is possible?
@@ -71,8 +71,8 @@ async def pm(evt):
return await evt.reply("That doesn't seem to be a user.")
portal = po.Portal.get_by_entity(user, evt.sender.tgid)
await portal.create_matrix_room(evt.sender, user, [evt.sender.mxid])
return await evt.reply(
f"Created private chat room with {pu.Puppet.get_displayname(user, False)}")
return await evt.reply("Created private chat room with "
f"{pu.Puppet.get_displayname(user, False)}")
@command_handler()
@@ -116,9 +116,9 @@ async def delete_portal(evt):
"action": "Portal deletion",
}
return await evt.reply("Please confirm deletion of portal "
+ f"[{room_id}](https://matrix.to/#/{room_id}) "
+ f"to Telegram chat \"{portal.title}\" "
+ "by typing `$cmdprefix+sp confirm-delete`")
f"[{room_id}](https://matrix.to/#/{room_id}) "
f"to Telegram chat \"{portal.title}\" "
"by typing `$cmdprefix+sp confirm-delete`")
@command_handler()
@@ -151,11 +151,12 @@ async def join(evt):
for chat in updates.chats:
portal = po.Portal.get_by_entity(chat)
if portal.mxid:
await portal.invite_to_matrix([evt.sender.mxid])
return await evt.reply(f"Invited you to portal of {portal.title}")
else:
await evt.reply(f"Creating room for {chat.title}... This might take a while.")
await portal.create_matrix_room(evt.sender, chat, [evt.sender.mxid])
return await evt.reply(f"Created room for {portal.title}")
else:
await portal.invite_matrix([evt.sender.mxid])
return await evt.reply(f"Invited you to portal of {portal.title}")
@command_handler()
@@ -183,16 +184,16 @@ async def create(evt):
return await evt.reply("Please set a title before creating a Telegram chat.")
elif (not levels or not levels["users"] or evt.az.intent.mxid not in levels["users"] or
levels["users"][evt.az.intent.mxid] < 100):
return await evt.reply(f"Please give "
+ f"[the bridge bot](https://matrix.to/#/{evt.az.intent.mxid})"
+ f" a power level of 100 before creating a Telegram chat.")
return await evt.reply("Please give "
f"[the bridge bot](https://matrix.to/#/{evt.az.intent.mxid})"
" a power level of 100 before creating a Telegram chat.")
else:
for user, level in levels["users"].items():
if level >= 100 and user != evt.az.intent.mxid:
return await evt.reply(
f"Please make sure only the bridge bot has power level above"
+ f"99 before creating a Telegram chat.\n\n"
+ f"Use power level 95 instead of 100 for admins.")
f"99 before creating a Telegram chat.\n\n"
f"Use power level 95 instead of 100 for admins.")
supergroup = type == "supergroup"
type = {