Compare commits

...

14 Commits

Author SHA1 Message Date
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
Tulir Asokan 961707dd30 Bump version to 0.2.0rc2 2018-05-21 00:39:27 +03:00
Tulir Asokan 90197f1a40 Update links in README so they work on docker hub 2018-05-21 00:39:13 +03:00
Tulir Asokan 53a7111550 Merge pull request #137 from jcgruenhage/master
fix ffmpeg in docker
2018-05-21 00:25:02 +03:00
Jan Christian Grünhage 78d1f92c13 fix ffmpeg in docker 2018-05-20 23:22:07 +02:00
Tulir Asokan 37b13fe31b Merge pull request #136 from jcgruenhage/docker
Add Dockerfile
2018-05-20 16:10:06 +03:00
Jan Christian Grünhage 39c9548983 add Dockerfile 2018-05-20 14:39:28 +02:00
15 changed files with 122 additions and 36 deletions
+30
View File
@@ -0,0 +1,30 @@
FROM docker.io/alpine:3.7
ENV UID=1337 \
GID=1337
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 \
ffmpeg \
bash \
ca-certificates \
su-exec \
s6 \
&& cd /opt/mautrixtelegram \
&& cp -r docker/root/* / \
&& rm docker -rf \
&& pip3 install -r requirements.txt -r optional-requirements.txt
VOLUME /data
CMD ["/bin/s6-svscan", "/etc/s6.d"]
+2 -2
View File
@@ -3,7 +3,7 @@ A Matrix-Telegram hybrid puppeting/relaybot bridge.
### [Wiki](https://github.com/tulir/mautrix-telegram/wiki) ### [Wiki](https://github.com/tulir/mautrix-telegram/wiki)
### [Features & Roadmap](ROADMAP.md) ### [Features & Roadmap](https://github.com/tulir/mautrix-telegram/blob/master/ROADMAP.md)
## Discussion ## Discussion
Matrix room: [`#telegram:maunium.net`](https://matrix.to/#/#telegram:maunium.net) Matrix room: [`#telegram:maunium.net`](https://matrix.to/#/#telegram:maunium.net)
@@ -11,4 +11,4 @@ Matrix room: [`#telegram:maunium.net`](https://matrix.to/#/#telegram:maunium.net
Telegram chat: [`mautrix_telegram`](https://t.me/mautrix_telegram) (bridged to Matrix room) Telegram chat: [`mautrix_telegram`](https://t.me/mautrix_telegram) (bridged to Matrix room)
## Preview ## Preview
![Preview](preview.png) ![Preview](https://raw.githubusercontent.com/tulir/mautrix-telegram/master/preview.png)
-3
View File
@@ -35,9 +35,6 @@ script_location = alembic
# are written from script.py.mako # are written from script.py.mako
# output_encoding = utf-8 # output_encoding = utf-8
sqlalchemy.url = sqlite:///mautrix-telegram.db
# Logging configuration # Logging configuration
[loggers] [loggers]
keys = root,sqlalchemy,alembic keys = root,sqlalchemy,alembic
+7 -1
View File
@@ -1,4 +1,3 @@
from __future__ import with_statement
from alembic import context from alembic import context
from sqlalchemy import engine_from_config, pool from sqlalchemy import engine_from_config, pool
from logging.config import fileConfig from logging.config import fileConfig
@@ -8,12 +7,19 @@ from os.path import abspath, dirname
sys.path.insert(0, dirname(dirname(abspath(__file__)))) sys.path.insert(0, dirname(dirname(abspath(__file__))))
from mautrix_telegram.base import Base from mautrix_telegram.base import Base
from mautrix_telegram.config import Config
import mautrix_telegram.db import mautrix_telegram.db
# this is the Alembic Config object, which provides # this is the Alembic Config object, which provides
# access to the values within the .ini file in use. # access to the values within the .ini file in use.
config = context.config 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. # Interpret the config file for Python logging.
# This line sets up loggers basically. # This line sets up loggers basically.
fileConfig(config.config_file_name) fileConfig(config.config_file_name)
@@ -19,31 +19,31 @@ depends_on = None
def upgrade(): def upgrade():
Session = op.create_table('telethon_sessions', Session = op.create_table('telethon_sessions',
sa.Column('session_id', sa.VARCHAR(), nullable=False), sa.Column('session_id', sa.String, nullable=False),
sa.Column('dc_id', sa.INTEGER(), nullable=False), sa.Column('dc_id', sa.Integer, nullable=False),
sa.Column('server_address', sa.VARCHAR(), nullable=True), sa.Column('server_address', sa.String, nullable=True),
sa.Column('port', sa.INTEGER(), nullable=True), sa.Column('port', sa.Integer, nullable=True),
sa.Column('auth_key', sa.BLOB(), nullable=True), sa.Column('auth_key', sa.LargeBinary, nullable=True),
sa.PrimaryKeyConstraint('session_id', 'dc_id')) sa.PrimaryKeyConstraint('session_id', 'dc_id'))
SentFile = op.create_table('telethon_sent_files', SentFile = op.create_table('telethon_sent_files',
sa.Column('session_id', sa.VARCHAR(), nullable=False), sa.Column('session_id', sa.String, nullable=False),
sa.Column('md5_digest', sa.BLOB(), nullable=False), sa.Column('md5_digest', sa.LargeBinary, nullable=False),
sa.Column('file_size', sa.INTEGER(), nullable=False), sa.Column('file_size', sa.Integer, nullable=False),
sa.Column('type', sa.INTEGER(), nullable=False), sa.Column('type', sa.Integer, nullable=False),
sa.Column('id', sa.INTEGER(), nullable=True), sa.Column('id', sa.BigInteger, nullable=True),
sa.Column('hash', sa.INTEGER(), nullable=True), sa.Column('hash', sa.BigInteger, nullable=True),
sa.PrimaryKeyConstraint('session_id', 'md5_digest', 'file_size', sa.PrimaryKeyConstraint('session_id', 'md5_digest', 'file_size',
'type')) 'type'))
Entity = op.create_table('telethon_entities', Entity = op.create_table('telethon_entities',
sa.Column('session_id', sa.VARCHAR(), nullable=False), sa.Column('session_id', sa.String, nullable=False),
sa.Column('id', sa.INTEGER(), nullable=False), sa.Column('id', sa.Integer, nullable=False),
sa.Column('hash', sa.INTEGER(), nullable=False), sa.Column('hash', sa.Integer, nullable=False),
sa.Column('username', sa.VARCHAR(), nullable=True), sa.Column('username', sa.String, nullable=True),
sa.Column('phone', sa.INTEGER(), nullable=True), sa.Column('phone', sa.Integer, nullable=True),
sa.Column('name', sa.VARCHAR(), nullable=True), sa.Column('name', sa.String, nullable=True),
sa.PrimaryKeyConstraint('session_id', 'id')) sa.PrimaryKeyConstraint('session_id', 'id'))
Version = op.create_table('telethon_version', Version = op.create_table('telethon_version',
sa.Column('version', sa.INTEGER(), nullable=False), sa.Column('version', sa.Integer, nullable=False),
sa.PrimaryKeyConstraint('version')) sa.PrimaryKeyConstraint('version'))
conn = op.get_bind() conn = op.get_bind()
sessions = [os.path.basename(f) for f in os.listdir(".") if f.endswith(".session")] sessions = [os.path.basename(f) for f in os.listdir(".") if f.endswith(".session")]
@@ -18,7 +18,7 @@ depends_on = None
def upgrade(): def upgrade():
op.add_column('telegram_file', op.add_column('telegram_file',
sa.Column('timestamp', sa.BigInteger(), nullable=False, default=0, sa.Column('timestamp', sa.BigInteger(), nullable=False, default=0,
server_default="true")) server_default="0"))
def downgrade(): def downgrade():
@@ -29,7 +29,7 @@ def upgrade():
sa.UniqueConstraint('mxid')) sa.UniqueConstraint('mxid'))
op.create_table('user', op.create_table('user',
sa.Column('mxid', sa.String), 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('tg_username', sa.String, nullable=True),
sa.Column('saved_contacts', sa.Integer, nullable=False, default=0), sa.Column('saved_contacts', sa.Integer, nullable=False, default=0),
sa.PrimaryKeyConstraint('mxid')) sa.PrimaryKeyConstraint('mxid'))
+1
View File
@@ -0,0 +1 @@
#!/bin/sh
+2
View File
@@ -0,0 +1,2 @@
#!/bin/bash
s6-svscanctl -t /etc/s6.d
+39
View File
@@ -0,0 +1,39 @@
#!/bin/bash
# Define functions
function fixperms {
chown -R ${UID}:${GID} /data /opt/mautrixtelegram
}
# Go into env
cd /opt/mautrixtelegram
export FFMPEG_BINARY=/usr/bin/ffmpeg
# 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 -x config=/data/config.yaml upgrade head
if [[ ! -f /data/config.yaml ]]; then
cp example-config.yaml /data/config.yaml
echo "Didn't find a config file."
echo "Copied default config file to /data/config.yaml"
echo "Modify that config file to your liking."
echo "Start the container again after that to generate the registration file."
fixperms
exit
fi
if [[ ! -f /data/registration.yaml ]]; then
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."
fixperms
exit
fi
fixperms
exec su-exec ${UID}:${GID} python3 -m mautrix_telegram -c /data/config.yaml
+1 -1
View File
@@ -1,2 +1,2 @@
__version__ = "0.2.0rc1" __version__ = "0.2.0rc4"
__author__ = "Tulir Asokan <tulir@maunium.net>" __author__ = "Tulir Asokan <tulir@maunium.net>"
+1 -1
View File
@@ -26,7 +26,7 @@ from alchemysession import AlchemySessionContainer
from mautrix_appservice import AppService from mautrix_appservice import AppService
from .base import Base from .base import Base
from .config import Config, DictWithRecursion from .config import Config
from .matrix import MatrixHandler from .matrix import MatrixHandler
from .db import init as init_db 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): if not self.mxid_regex.match(mxid):
return await reply("That doesn't look like a Matrix ID.") return await reply("That doesn't look like a Matrix ID.")
user = await u.User.get_by_mxid(mxid).ensure_started() 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.") return await reply("That user is not whitelisted to use the bridge.")
elif user.logged_in: elif user.logged_in:
displayname = f"@{user.username}" if user.username else user.displayname displayname = f"@{user.username}" if user.username else user.displayname
+17 -6
View File
@@ -102,7 +102,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): async def delete_portal(evt: CommandEvent):
portal, ok = await _get_portal_and_check_permission(evt, "delete_portal") portal, ok = await _get_portal_and_check_permission(evt, "delete_portal")
if not ok: if not ok:
@@ -117,7 +117,7 @@ async def delete_portal(evt: CommandEvent):
"by typing `$cmdprefix+sp confirm-delete`") "by typing `$cmdprefix+sp confirm-delete`")
@command_handler() @command_handler(needs_auth=False)
async def unbridge(evt: CommandEvent): async def unbridge(evt: CommandEvent):
portal, ok = await _get_portal_and_check_permission(evt, "unbridge_room") portal, ok = await _get_portal_and_check_permission(evt, "unbridge_room")
if not ok: if not ok:
@@ -131,7 +131,7 @@ async def unbridge(evt: CommandEvent):
"by typing `$cmdprefix+sp confirm-unbridge`") "by typing `$cmdprefix+sp confirm-unbridge`")
@command_handler() @command_handler(needs_auth=False)
async def bridge(evt: CommandEvent): async def bridge(evt: CommandEvent):
if len(evt.args) == 0: if len(evt.args) == 0:
return await evt.reply("**Usage:** " return await evt.reply("**Usage:** "
@@ -247,14 +247,25 @@ async def confirm_bridge(evt: CommandEvent):
return await evt.reply("Please use `$cmdprefix+sp continue` to confirm the bridging or " return await evt.reply("Please use `$cmdprefix+sp continue` to confirm the bridging or "
"`$cmdprefix+sp cancel` to cancel.") "`$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?")
direct = False
portal.mxid = bridge_to_mxid portal.mxid = bridge_to_mxid
portal.title, portal.about, levels = await _get_initial_state(evt) portal.title, portal.about, levels = await _get_initial_state(evt)
portal.photo_id = "" portal.photo_id = ""
portal.save() portal.save()
entity = await evt.sender.client.get_entity(portal.peer) asyncio.ensure_future(portal.update_matrix_room(user, entity, direct, levels=levels),
direct = False
asyncio.ensure_future(portal.update_matrix_room(evt.sender, entity, direct, levels=levels),
loop=evt.loop) loop=evt.loop)
return await evt.reply("Bridging complete. Portal synchronization should begin momentarily.") return await evt.reply("Bridging complete. Portal synchronization should begin momentarily.")
+1 -1
View File
@@ -70,7 +70,7 @@ class User(Base):
__tablename__ = "user" __tablename__ = "user"
mxid = Column(String, primary_key=True) mxid = Column(String, primary_key=True)
tgid = Column(Integer, nullable=True) tgid = Column(Integer, nullable=True, unique=True)
tg_username = Column(String, nullable=True) tg_username = Column(String, nullable=True)
saved_contacts = Column(Integer, default=0) saved_contacts = Column(Integer, default=0)
contacts = relationship("Contact", uselist=True, contacts = relationship("Contact", uselist=True,