Compare commits

..

12 Commits

Author SHA1 Message Date
Tulir Asokan 844cf14bcd Bump version to 0.2.0rc5 2018-06-01 13:27:20 +03:00
Tulir Asokan fe32475e10 Fix kicking Telegram puppets and fix error message when bridging chats you've left 2018-05-31 11:19:24 +03:00
Tulir Asokan f28f5915a4 Don't create portal in response to relaybot events. Fixes #145 2018-05-31 11:18:48 +03:00
Tulir Asokan 1aa80c1a8f Fix user_portal delete cascade when deleting portals 2018-05-31 11:18:20 +03:00
Tulir Asokan 5d9b94fa5f Bump version to 0.2.0rc4 2018-05-29 22:26:26 +03:00
Tulir Asokan 6ef31599e9 Read database path from config in alembic env.py
Slightly related to #135
2018-05-29 18:37:08 +03:00
Tulir Asokan e961e0bcc6 Fix manual bridging using the relay bot 2018-05-29 15:26:40 +03:00
Tulir Asokan dc85754b1e Fix postgres compatibility 2018-05-29 15:17:08 +03:00
Tulir Asokan 04e2c03dae Allow inviting relaybot-whitelisted Matrix users to portal from telegram 2018-05-29 15:15:42 +03:00
Tulir Asokan 42d54dac5b Bump version to 0.2.0rc3 2018-05-25 00:08:46 +03:00
Tulir Asokan 767a51f994 Merge pull request #142 from jcgruenhage/master
Rework Dockerfile to remove virtualenv
2018-05-25 00:07:57 +03:00
Jan Christian Grünhage 313b5e5d07 rework Dockerfile to remove virtualenv 2018-05-24 00:59:26 +02:00
15 changed files with 106 additions and 54 deletions
+8 -8
View File
@@ -7,12 +7,14 @@ COPY . /opt/mautrixtelegram
RUN apk add --no-cache \
python3-dev \
py3-virtualenv \
py3-pillow \
py3-aiohttp \
py3-lxml \
py3-magic \
py3-numpy \
py3-asn1crypto \
py3-sqlalchemy \
build-base \
zlib-dev \
jpeg-dev \
libxslt-dev \
libxml2-dev \
libmagic \
ffmpeg \
bash \
ca-certificates \
@@ -21,9 +23,7 @@ RUN apk add --no-cache \
&& cd /opt/mautrixtelegram \
&& cp -r docker/root/* / \
&& rm docker -rf \
&& virtualenv -p /usr/bin/python3 .venv \
&& source .venv/bin/activate \
&& pip install -r requirements.txt -r optional-requirements.txt
&& pip3 install -r requirements.txt -r optional-requirements.txt
VOLUME /data
-3
View File
@@ -35,9 +35,6 @@ script_location = alembic
# are written from script.py.mako
# output_encoding = utf-8
sqlalchemy.url = sqlite:///mautrix-telegram.db
# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic
+7 -1
View File
@@ -1,4 +1,3 @@
from __future__ import with_statement
from alembic import context
from sqlalchemy import engine_from_config, pool
from logging.config import fileConfig
@@ -8,12 +7,19 @@ from os.path import abspath, dirname
sys.path.insert(0, dirname(dirname(abspath(__file__))))
from mautrix_telegram.base import Base
from mautrix_telegram.config import Config
import mautrix_telegram.db
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
mxtg_config_path = context.get_x_argument(as_dictionary=True).get("config", "config.yaml")
mxtg_config = Config(mxtg_config_path, None, None)
mxtg_config.load()
config.set_main_option("sqlalchemy.url",
mxtg_config.get("appservice.database", "sqlite:///mautrix-telegram.db"))
# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
@@ -0,0 +1,30 @@
"""Add cascade rules to UserPortal
Revision ID: 2228d49c383f
Revises: bcfefa1f1299
Create Date: 2018-05-31 11:11:59.482112
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision = '2228d49c383f'
down_revision = 'bcfefa1f1299'
branch_labels = None
depends_on = None
def upgrade():
op.drop_constraint('user_portal_user_fkey', 'user_portal', type_='foreignkey')
op.drop_constraint('user_portal_portal_fkey', 'user_portal', type_='foreignkey')
op.create_foreign_key('user_portal_user_fkey', 'user_portal', 'user', ['user'], ['tgid'], onupdate='CASCADE', ondelete='CASCADE')
op.create_foreign_key('user_portal_portal_fkey', 'user_portal', 'portal', ['portal', 'portal_receiver'], ['tgid', 'tg_receiver'], onupdate='CASCADE', ondelete='CASCADE')
def downgrade():
op.drop_constraint('user_portal_portal_fkey', 'user_portal', type_='foreignkey')
op.drop_constraint('user_portal_user_fkey', 'user_portal', type_='foreignkey')
op.create_foreign_key('user_portal_portal_fkey', 'user_portal', 'portal', ['portal', 'portal_receiver'], ['tgid', 'tg_receiver'])
op.create_foreign_key('user_portal_user_fkey', 'user_portal', 'user', ['user'], ['tgid'])
@@ -19,31 +19,31 @@ depends_on = None
def upgrade():
Session = op.create_table('telethon_sessions',
sa.Column('session_id', sa.VARCHAR(), nullable=False),
sa.Column('dc_id', sa.INTEGER(), nullable=False),
sa.Column('server_address', sa.VARCHAR(), nullable=True),
sa.Column('port', sa.INTEGER(), nullable=True),
sa.Column('auth_key', sa.BLOB(), nullable=True),
sa.Column('session_id', sa.String, nullable=False),
sa.Column('dc_id', sa.Integer, nullable=False),
sa.Column('server_address', sa.String, nullable=True),
sa.Column('port', sa.Integer, nullable=True),
sa.Column('auth_key', sa.LargeBinary, nullable=True),
sa.PrimaryKeyConstraint('session_id', 'dc_id'))
SentFile = op.create_table('telethon_sent_files',
sa.Column('session_id', sa.VARCHAR(), nullable=False),
sa.Column('md5_digest', sa.BLOB(), nullable=False),
sa.Column('file_size', sa.INTEGER(), nullable=False),
sa.Column('type', sa.INTEGER(), nullable=False),
sa.Column('id', sa.INTEGER(), nullable=True),
sa.Column('hash', sa.INTEGER(), nullable=True),
sa.Column('session_id', sa.String, nullable=False),
sa.Column('md5_digest', sa.LargeBinary, nullable=False),
sa.Column('file_size', sa.Integer, nullable=False),
sa.Column('type', sa.Integer, nullable=False),
sa.Column('id', sa.BigInteger, nullable=True),
sa.Column('hash', sa.BigInteger, nullable=True),
sa.PrimaryKeyConstraint('session_id', 'md5_digest', 'file_size',
'type'))
Entity = op.create_table('telethon_entities',
sa.Column('session_id', sa.VARCHAR(), nullable=False),
sa.Column('id', sa.INTEGER(), nullable=False),
sa.Column('hash', sa.INTEGER(), nullable=False),
sa.Column('username', sa.VARCHAR(), nullable=True),
sa.Column('phone', sa.INTEGER(), nullable=True),
sa.Column('name', sa.VARCHAR(), nullable=True),
sa.Column('session_id', sa.String, nullable=False),
sa.Column('id', sa.Integer, nullable=False),
sa.Column('hash', sa.Integer, nullable=False),
sa.Column('username', sa.String, nullable=True),
sa.Column('phone', sa.Integer, nullable=True),
sa.Column('name', sa.String, nullable=True),
sa.PrimaryKeyConstraint('session_id', 'id'))
Version = op.create_table('telethon_version',
sa.Column('version', sa.INTEGER(), nullable=False),
sa.Column('version', sa.Integer, nullable=False),
sa.PrimaryKeyConstraint('version'))
conn = op.get_bind()
sessions = [os.path.basename(f) for f in os.listdir(".") if f.endswith(".session")]
@@ -18,7 +18,7 @@ depends_on = None
def upgrade():
op.add_column('telegram_file',
sa.Column('timestamp', sa.BigInteger(), nullable=False, default=0,
server_default="true"))
server_default="0"))
def downgrade():
@@ -29,7 +29,7 @@ def upgrade():
sa.UniqueConstraint('mxid'))
op.create_table('user',
sa.Column('mxid', sa.String),
sa.Column('tgid', sa.Integer, nullable=True),
sa.Column('tgid', sa.Integer, nullable=True, unique=True),
sa.Column('tg_username', sa.String, nullable=True),
sa.Column('saved_contacts', sa.Integer, nullable=False, default=0),
sa.PrimaryKeyConstraint('mxid'))
+5 -8
View File
@@ -8,14 +8,13 @@ function fixperms {
# Go into env
cd /opt/mautrixtelegram
source .venv/bin/activate
export FFMPEG_BINARY=/usr/bin/ffmpeg
# Replace database path in alembic.ini
sed -i "s#sqlite:///mautrix-telegram.db#sqlite:////data/mautrix-telegram.db#" alembic.ini
# Replace database path in config.
sed -i "s#sqlite:///mautrix-telegram.db#sqlite:////data/mautrix-telegram.db#" /data/config.yaml
# Check that database is in the right state
alembic upgrade head
alembic -x config=/data/config.yaml upgrade head
if [[ ! -f /data/config.yaml ]]; then
cp example-config.yaml /data/config.yaml
@@ -28,7 +27,7 @@ if [[ ! -f /data/config.yaml ]]; then
fi
if [[ ! -f /data/registration.yaml ]]; then
python -m mautrix_telegram -g -c /data/config.yaml -r /data/registration.yaml
python3 -m mautrix_telegram -g -c /data/config.yaml -r /data/registration.yaml
echo "Didn't find a registration file."
echo "Generated ode for you."
echo "Copy that over to synapses app service directory."
@@ -36,7 +35,5 @@ if [[ ! -f /data/registration.yaml ]]; then
exit
fi
export FFMPEG_BINARY=/usr/bin/ffmpeg
fixperms
exec su-exec ${UID}:${GID} python -m mautrix_telegram -c /data/config.yaml
exec su-exec ${UID}:${GID} python3 -m mautrix_telegram -c /data/config.yaml
+1 -1
View File
@@ -1,2 +1,2 @@
__version__ = "0.2.0rc2"
__version__ = "0.2.0rc5"
__author__ = "Tulir Asokan <tulir@maunium.net>"
+1 -1
View File
@@ -26,7 +26,7 @@ from alchemysession import AlchemySessionContainer
from mautrix_appservice import AppService
from .base import Base
from .config import Config, DictWithRecursion
from .config import Config
from .matrix import MatrixHandler
from .db import init as init_db
+1 -1
View File
@@ -166,7 +166,7 @@ class Bot(AbstractUser):
if not self.mxid_regex.match(mxid):
return await reply("That doesn't look like a Matrix ID.")
user = await u.User.get_by_mxid(mxid).ensure_started()
if not user.whitelisted:
if not user.relaybot_whitelisted:
return await reply("That user is not whitelisted to use the bridge.")
elif user.logged_in:
displayname = f"@{user.username}" if user.username else user.displayname
+24 -6
View File
@@ -17,6 +17,7 @@
import asyncio
from telethon.errors import *
from telethon.tl.types import ChatForbidden, ChannelForbidden
from mautrix_appservice import MatrixRequestError
from .. import portal as po
@@ -102,7 +103,7 @@ def _get_portal_murder_function(action, room_id, function, command, completed_me
}
@command_handler()
@command_handler(needs_auth=False)
async def delete_portal(evt: CommandEvent):
portal, ok = await _get_portal_and_check_permission(evt, "delete_portal")
if not ok:
@@ -117,7 +118,7 @@ async def delete_portal(evt: CommandEvent):
"by typing `$cmdprefix+sp confirm-delete`")
@command_handler()
@command_handler(needs_auth=False)
async def unbridge(evt: CommandEvent):
portal, ok = await _get_portal_and_check_permission(evt, "unbridge_room")
if not ok:
@@ -131,7 +132,7 @@ async def unbridge(evt: CommandEvent):
"by typing `$cmdprefix+sp confirm-unbridge`")
@command_handler()
@command_handler(needs_auth=False)
async def bridge(evt: CommandEvent):
if len(evt.args) == 0:
return await evt.reply("**Usage:** "
@@ -247,14 +248,31 @@ async def confirm_bridge(evt: CommandEvent):
return await evt.reply("Please use `$cmdprefix+sp continue` to confirm the bridging or "
"`$cmdprefix+sp cancel` to cancel.")
user = evt.sender if evt.sender.logged_in else evt.tgbot
try:
entity = await user.client.get_entity(portal.peer)
except Exception:
evt.log.exception("Failed to get_entity(%s) for manual bridging.", portal.peer)
if evt.sender.logged_in:
return await evt.reply("Failed to get info of telegram chat. "
"You are logged in, are you in that chat?")
else:
return await evt.reply("Failed to get info of telegram chat. "
"You're not logged in, is the relay bot in the chat?")
if isinstance(entity, (ChatForbidden, ChannelForbidden)):
if evt.sender.logged_in:
return await evt.reply("You don't seem to be in that chat.")
else:
return await evt.reply("The bot doesn't seem to be in that chat.")
direct = False
portal.mxid = bridge_to_mxid
portal.title, portal.about, levels = await _get_initial_state(evt)
portal.photo_id = ""
portal.save()
entity = await evt.sender.client.get_entity(portal.peer)
direct = False
asyncio.ensure_future(portal.update_matrix_room(evt.sender, entity, direct, levels=levels),
asyncio.ensure_future(portal.update_matrix_room(user, entity, direct, levels=levels),
loop=evt.loop)
return await evt.reply("Bridging complete. Portal synchronization should begin momentarily.")
+5 -3
View File
@@ -57,12 +57,14 @@ class UserPortal(Base):
query = None
__tablename__ = "user_portal"
user = Column(Integer, ForeignKey("user.tgid"), primary_key=True)
user = Column(Integer, ForeignKey("user.tgid", onupdate="CASCADE", ondelete="CASCADE"),
primary_key=True)
portal = Column(Integer, primary_key=True)
portal_receiver = Column(Integer, primary_key=True)
__table_args__ = (ForeignKeyConstraint(("portal", "portal_receiver"),
("portal.tgid", "portal.tg_receiver")),)
("portal.tgid", "portal.tg_receiver"),
onupdate="CASCADE", ondelete="CASCADE"),)
class User(Base):
@@ -70,7 +72,7 @@ class User(Base):
__tablename__ = "user"
mxid = Column(String, primary_key=True)
tgid = Column(Integer, nullable=True)
tgid = Column(Integer, nullable=True, unique=True)
tg_username = Column(String, nullable=True)
saved_contacts = Column(Integer, default=0)
contacts = relationship("Contact", uselist=True,
+1 -1
View File
@@ -154,7 +154,7 @@ class MatrixHandler:
puppet = Puppet.get_by_mxid(user)
if sender and puppet:
await portal.leave_matrix(puppet, sender)
await portal.leave_matrix(puppet, sender, event_id)
user = User.get_by_mxid(user, create=False)
if not user:
+3 -1
View File
@@ -1318,6 +1318,8 @@ class Portal:
await intent.redact(self.mxid, mxid)
async def _create_room_on_action(self, source, action):
if source.is_relaybot:
return False
create_and_exit = (MessageActionChatCreate, MessageActionChannelCreate)
create_and_continue = (MessageActionChatAddUser, MessageActionChatJoinedByLink)
if isinstance(action, create_and_exit + create_and_continue):
@@ -1331,7 +1333,7 @@ class Portal:
action = update.action
should_ignore = ((not self.mxid and not await self._create_room_on_action(source, action))
or self.is_duplicate_action(update))
if should_ignore:
if should_ignore or not self.mxid:
return
# TODO figure out how to see changes to about text / channel username
if isinstance(action, MessageActionChatEditTitle):