replaced sqlalchemy with peewee for orm and revamped schema
Also covers issue #62
This commit is contained in:
parent
734be1edda
commit
3d96f910ee
5 changed files with 263 additions and 404 deletions
|
@ -17,11 +17,11 @@ dependencies = [
|
||||||
"requests",
|
"requests",
|
||||||
"Flask[async]",
|
"Flask[async]",
|
||||||
"pnutpy>=0.5.0",
|
"pnutpy>=0.5.0",
|
||||||
"sqlalchemy",
|
|
||||||
"filemagic",
|
"filemagic",
|
||||||
"mautrix>=0.20.6,<0.21",
|
"mautrix>=0.20.6,<0.21",
|
||||||
"websockets",
|
"websockets",
|
||||||
"asyncclick",
|
"asyncclick",
|
||||||
|
"peewee",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
|
|
|
@ -11,10 +11,7 @@ import os
|
||||||
|
|
||||||
from mautrix.client import ClientAPI
|
from mautrix.client import ClientAPI
|
||||||
from mautrix.types import *
|
from mautrix.types import *
|
||||||
|
from pnut_matrix.models import *
|
||||||
from pnut_matrix.models import Avatars, Rooms, Events, Users, DirectRooms, ControlRooms
|
|
||||||
from pnut_matrix.database import db_session
|
|
||||||
from sqlalchemy import and_
|
|
||||||
from flask import Flask, jsonify, request, abort
|
from flask import Flask, jsonify, request, abort
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -29,10 +26,6 @@ def not_found(error):
|
||||||
def forbidden(error):
|
def forbidden(error):
|
||||||
return jsonify({'errcode':'PNUT_FORBIDDEN'}), 403
|
return jsonify({'errcode':'PNUT_FORBIDDEN'}), 403
|
||||||
|
|
||||||
@app.teardown_appcontext
|
|
||||||
def shutdown_session(exception=None):
|
|
||||||
db_session.remove()
|
|
||||||
|
|
||||||
@app.route("/_matrix/app/v1/rooms/<alias>")
|
@app.route("/_matrix/app/v1/rooms/<alias>")
|
||||||
@app.route("/rooms/<alias>")
|
@app.route("/rooms/<alias>")
|
||||||
async def query_alias(alias):
|
async def query_alias(alias):
|
||||||
|
@ -40,7 +33,8 @@ async def query_alias(alias):
|
||||||
alias_localpart = alias.split(":")[0][1:]
|
alias_localpart = alias.split(":")[0][1:]
|
||||||
channel_id = int(alias_localpart.split('_')[1])
|
channel_id = int(alias_localpart.split('_')[1])
|
||||||
|
|
||||||
room = Rooms.query.filter(Rooms.pnut_chan == channel_id).one_or_none()
|
room = PnutChannels.select().where(PnutChannels.pnut_chan ==
|
||||||
|
channel_id).first()
|
||||||
if room is not None:
|
if room is not None:
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
|
@ -58,9 +52,9 @@ async def query_alias(alias):
|
||||||
if 'io.pnut.core.chat-settings' in channel.raw:
|
if 'io.pnut.core.chat-settings' in channel.raw:
|
||||||
for setting in channel.raw['io.pnut.core.chat-settings']:
|
for setting in channel.raw['io.pnut.core.chat-settings']:
|
||||||
if 'name' in setting:
|
if 'name' in setting:
|
||||||
name = setting['name']
|
name = f"🥜 {setting['name']}"
|
||||||
else:
|
else:
|
||||||
name = None
|
name = f"🥜 channel {channel.id}"
|
||||||
if 'description' in setting:
|
if 'description' in setting:
|
||||||
topic = setting['description']['text']
|
topic = setting['description']['text']
|
||||||
else:
|
else:
|
||||||
|
@ -84,15 +78,11 @@ async def query_alias(alias):
|
||||||
|
|
||||||
if not channel.you_subscribed:
|
if not channel.you_subscribed:
|
||||||
pnutpy.api.subscribe_channel(channel_id)
|
pnutpy.api.subscribe_channel(channel_id)
|
||||||
rr = Rooms(
|
|
||||||
room_id=room_id,
|
room = PnutChannels(room_id=room_id, pnut_chan=channel_id)
|
||||||
pnut_chan=channel_id,
|
room.save()
|
||||||
portal=True
|
logging.debug(f'-created new room for channel {room.pnut_chan}-')
|
||||||
)
|
logging.debug(room.room_id)
|
||||||
logging.debug(rr.room_id)
|
|
||||||
logging.debug(rr.pnut_chan)
|
|
||||||
db_session.add(rr)
|
|
||||||
db_session.commit()
|
|
||||||
|
|
||||||
except pnutpy.errors.PnutPermissionDenied:
|
except pnutpy.errors.PnutPermissionDenied:
|
||||||
logging.debug("-permission denied-")
|
logging.debug("-permission denied-")
|
||||||
|
@ -114,23 +104,25 @@ async def on_receive_events(transaction):
|
||||||
|
|
||||||
events = request.get_json()["events"]
|
events = request.get_json()["events"]
|
||||||
for event in events:
|
for event in events:
|
||||||
|
logging.debug('-----event-----')
|
||||||
logging.debug(event)
|
logging.debug(event)
|
||||||
|
logging.debug('~~~~~~~~~~~~~~~')
|
||||||
|
|
||||||
if (app.config['MATRIX_ADMIN_ROOM'] and
|
if (app.config['MATRIX_ADMIN_ROOM'] and
|
||||||
app.config['MATRIX_ADMIN_ROOM'] == event['room_id']):
|
app.config['MATRIX_ADMIN_ROOM'] == event['room_id']):
|
||||||
|
logging.debug('>----on_admin_event----<')
|
||||||
await on_admin_event(event)
|
await on_admin_event(event)
|
||||||
return jsonify({})
|
return jsonify({})
|
||||||
|
|
||||||
user = Users.query.filter(Users.matrix_id ==
|
user = PnutUsers.select().where(PnutUsers.matrix_id ==
|
||||||
event['sender']).one_or_none()
|
event['sender']).first()
|
||||||
|
|
||||||
if event['type'] == 'm.room.message':
|
if event['type'] == 'm.room.message':
|
||||||
|
logging.debug('>----new_message----<')
|
||||||
await new_message(event, user)
|
await new_message(event, user)
|
||||||
|
|
||||||
# elif event['type'] == 'm.sticker':
|
|
||||||
# new_sticker(event, user)
|
|
||||||
|
|
||||||
elif event['type'] == 'm.room.redaction':
|
elif event['type'] == 'm.room.redaction':
|
||||||
|
logging.debug('>----delete_message----<')
|
||||||
delete_message(event, user)
|
delete_message(event, user)
|
||||||
|
|
||||||
elif event['type'] == 'm.room.member':
|
elif event['type'] == 'm.room.member':
|
||||||
|
@ -138,59 +130,55 @@ async def on_receive_events(transaction):
|
||||||
'membership' in event['content']):
|
'membership' in event['content']):
|
||||||
if (event['content']['membership'] == "invite" and
|
if (event['content']['membership'] == "invite" and
|
||||||
event['content']['is_direct']):
|
event['content']['is_direct']):
|
||||||
logging.debug('----> direct invite <----')
|
logging.debug('>----on_direct_invite----<')
|
||||||
await on_direct_invite(event)
|
await on_direct_invite(event)
|
||||||
return jsonify({})
|
return jsonify({})
|
||||||
|
|
||||||
if 'membership' in event['content']:
|
if 'membership' in event['content']:
|
||||||
if event['content']['membership'] == "leave":
|
if event['content']['membership'] == "leave":
|
||||||
logging.debug('----> leave event <----')
|
logging.debug('>----on_leave_event----<')
|
||||||
await on_leave_event(event)
|
await on_leave_event(event)
|
||||||
return jsonify({})
|
return jsonify({})
|
||||||
|
|
||||||
logging.debug("----room member event----")
|
|
||||||
logging.debug(user)
|
|
||||||
logging.debug(event)
|
|
||||||
|
|
||||||
return jsonify({})
|
return jsonify({})
|
||||||
|
|
||||||
async def new_message(event, user):
|
async def new_message(event, user):
|
||||||
if (app.config['MATRIX_PNUT_PREFIX'] in event['sender'] or
|
|
||||||
'pnut-bridge' in event['sender']):
|
if event['sender'] == app.config['MATRIX_AS_ID']:
|
||||||
logging.debug('-skipping dup event-')
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if 'msgtype' not in event['content']:
|
if app.config['MATRIX_PNUT_PREFIX'] in event['sender']:
|
||||||
logging.debug('-unknown message type-')
|
|
||||||
return
|
return
|
||||||
|
|
||||||
control = ControlRooms.query.filter(ControlRooms.room_id ==
|
if user.room_id == event['room_id']:
|
||||||
event['room_id']).one_or_none()
|
await on_control_message(event, user)
|
||||||
if control is not None:
|
|
||||||
await on_control_message(event)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
direct = DirectRooms.query.filter(DirectRooms.room_id ==
|
room = PnutChannels.select().where(PnutChannels.room_id ==
|
||||||
event['room_id']).one_or_none()
|
event['room_id']).first()
|
||||||
if direct is not None:
|
logging.debug(f'room: {room}')
|
||||||
return on_direct_message(event, user, direct)
|
|
||||||
|
|
||||||
room = Rooms.query.filter(Rooms.room_id == event['room_id']).one_or_none()
|
|
||||||
if room is None:
|
if room is None:
|
||||||
logging.debug('-room not mapped-')
|
logging.debug('-room not mapped-')
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if room.is_direct:
|
||||||
|
logging.debug('>----on_direct_message----<')
|
||||||
|
return on_direct_message(event, user, room)
|
||||||
|
|
||||||
if user is not None:
|
if user is not None:
|
||||||
token = user.pnut_user_token
|
token = user.pnut_user_token
|
||||||
prefix = ""
|
prefix = ""
|
||||||
|
|
||||||
else:
|
else:
|
||||||
token = app.config['MATRIX_PNUT_TOKEN']
|
token = app.config['MATRIX_PNUT_TOKEN']
|
||||||
matrix_profile = get_profile(event['sender'])
|
matrix_profile = get_profile(event['sender'])
|
||||||
if "displayname" in matrix_profile:
|
if ('displayname' in matrix_profile):
|
||||||
prefix = (f"[{matrix_profile['displayname']}]"
|
prefix = (f"[{matrix_profile['displayname']}]"
|
||||||
f" ({event['sender']})\n")
|
f" ({event['sender']})\n")
|
||||||
else:
|
else:
|
||||||
prefix = "(" + event['sender'] + ")\n"
|
prefix = "(" + event['sender'] + ")\n"
|
||||||
|
|
||||||
pnutpy.api.add_authorization_token(token)
|
pnutpy.api.add_authorization_token(token)
|
||||||
|
|
||||||
raw = {}
|
raw = {}
|
||||||
|
@ -204,16 +192,13 @@ async def new_message(event, user):
|
||||||
try:
|
try:
|
||||||
msg, meta = pnutpy.api.create_message(room.pnut_chan,
|
msg, meta = pnutpy.api.create_message(room.pnut_chan,
|
||||||
data={'text': text, 'raw': raw})
|
data={'text': text, 'raw': raw})
|
||||||
revent = Events(
|
bridge_event = Events(
|
||||||
event_id=event['event_id'],
|
event_id=event['event_id'],
|
||||||
room_id=event['room_id'],
|
room_id=event['room_id'],
|
||||||
pnut_msg_id=msg.id,
|
pnut_id=msg.id,
|
||||||
pnut_user_id=msg.user.id,
|
pnut_channel=room.pnut_chan
|
||||||
pnut_chan_id=room.pnut_chan,
|
|
||||||
deleted=False
|
|
||||||
)
|
)
|
||||||
db_session.add(revent)
|
bridge_event.save()
|
||||||
db_session.commit()
|
|
||||||
|
|
||||||
# TODO: need to redo this for global message
|
# TODO: need to redo this for global message
|
||||||
# if user is not None:
|
# if user is not None:
|
||||||
|
@ -362,8 +347,8 @@ def delete_message(event, user):
|
||||||
token = app.config['MATRIX_PNUT_TOKEN']
|
token = app.config['MATRIX_PNUT_TOKEN']
|
||||||
pnutpy.api.add_authorization_token(token)
|
pnutpy.api.add_authorization_token(token)
|
||||||
|
|
||||||
e = Events.query.filter(and_(Events.event_id == event['redacts'],
|
e = Events.select().where((Events.event_id == events['redacts']) &
|
||||||
Events.deleted == False)).one_or_none()
|
(Events.deleted == False)).first()
|
||||||
if e is None:
|
if e is None:
|
||||||
logging.debug("- can't find the event to remove -")
|
logging.debug("- can't find the event to remove -")
|
||||||
return
|
return
|
||||||
|
@ -371,7 +356,7 @@ def delete_message(event, user):
|
||||||
try:
|
try:
|
||||||
r, meta = pnutpy.api.delete_message(e.pnut_chan_id, e.pnut_msg_id)
|
r, meta = pnutpy.api.delete_message(e.pnut_chan_id, e.pnut_msg_id)
|
||||||
e.deleted = True
|
e.deleted = True
|
||||||
db_session.commit()
|
e.save()
|
||||||
|
|
||||||
except pnutpy.errors.PnutPermissionDenied as e:
|
except pnutpy.errors.PnutPermissionDenied as e:
|
||||||
pass
|
pass
|
||||||
|
@ -406,9 +391,11 @@ async def create_pnut_matrix_room(channel, user):
|
||||||
if channel.acl.read.public:
|
if channel.acl.read.public:
|
||||||
visibility = RoomDirectoryVisibility.PUBLIC
|
visibility = RoomDirectoryVisibility.PUBLIC
|
||||||
preset = RoomCreatePreset.PUBLIC
|
preset = RoomCreatePreset.PUBLIC
|
||||||
|
is_private = False
|
||||||
else:
|
else:
|
||||||
visibility = RoomDirectoryVisibility.PRIVATE
|
visibility = RoomDirectoryVisibility.PRIVATE
|
||||||
preset = RoomCreatePreset.PRIVATE
|
preset = RoomCreatePreset.PRIVATE
|
||||||
|
is_private = True
|
||||||
|
|
||||||
if 'io.pnut.core.chat-settings' in channel.raw:
|
if 'io.pnut.core.chat-settings' in channel.raw:
|
||||||
for setting in channel.raw['io.pnut.core.chat-settings']:
|
for setting in channel.raw['io.pnut.core.chat-settings']:
|
||||||
|
@ -428,9 +415,20 @@ async def create_pnut_matrix_room(channel, user):
|
||||||
name=name,
|
name=name,
|
||||||
topic=topic)
|
topic=topic)
|
||||||
|
|
||||||
rr = Rooms(room_id=room_id, pnut_chan=channel.id, portal=True)
|
room = PnutChannels(room_id=room_id, pnut_chan=channel.id,
|
||||||
db_session.add(rr)
|
is_private=is_private)
|
||||||
db_session.commit()
|
room.save()
|
||||||
|
|
||||||
|
if is_private:
|
||||||
|
chan_member = PnutPrivateChanMembers(pnut_chan=channel.id,
|
||||||
|
room_id=room_id,
|
||||||
|
pnut_user_id=user.pnut_user_id,
|
||||||
|
matrix_id=user.matrix_id)
|
||||||
|
chan_member.save()
|
||||||
|
|
||||||
|
logging.debug('-create_pnut_matrix_room-')
|
||||||
|
logging.debug(f'-created new room for channel {room.pnut_chan}-')
|
||||||
|
logging.debug(room.room_id)
|
||||||
|
|
||||||
def new_matrix_user(username):
|
def new_matrix_user(username):
|
||||||
endpoint = "/_matrix/client/v3/register"
|
endpoint = "/_matrix/client/v3/register"
|
||||||
|
@ -479,22 +477,6 @@ async def on_admin_event(event):
|
||||||
elif msg[0] == 'list':
|
elif msg[0] == 'list':
|
||||||
await matrix_api.send_message(event['room_id'], cmd_admin_list())
|
await matrix_api.send_message(event['room_id'], cmd_admin_list())
|
||||||
|
|
||||||
elif msg[0] == 'unlink':
|
|
||||||
if len(msg) > 1:
|
|
||||||
await matrix_api.send_message(event['room_id'],
|
|
||||||
cmd_admin_unlink(msg[1]))
|
|
||||||
else:
|
|
||||||
await matrix_api.send_message(event['room_id'],
|
|
||||||
cmd_admin_help('unlink'))
|
|
||||||
|
|
||||||
elif msg[0] == 'link':
|
|
||||||
if len(msg) > 2:
|
|
||||||
await matrix_api.send_message(event['room_id'],
|
|
||||||
cmd_admin_link(msg[1], msg[2]))
|
|
||||||
else:
|
|
||||||
await matrix_api.send_message(event['room_id'],
|
|
||||||
cmd_admin_help('link'))
|
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
errmsg = "- on_admin_event -"
|
errmsg = "- on_admin_event -"
|
||||||
logging.exception(errmsg)
|
logging.exception(errmsg)
|
||||||
|
@ -504,10 +486,6 @@ def cmd_admin_help(cmd=None):
|
||||||
help_desc = "Show information about available commands."
|
help_desc = "Show information about available commands."
|
||||||
list_usage = "list"
|
list_usage = "list"
|
||||||
list_desc = "List the rooms currently linked with pnut.io."
|
list_desc = "List the rooms currently linked with pnut.io."
|
||||||
unlink_usage = "unlink <room_id> | <pnut_channel_id>"
|
|
||||||
unlink_desc = "Unlink a room between Matrix and pnut.io."
|
|
||||||
link_usage = "link <room_id> <pnut_channel_id>"
|
|
||||||
link_desc = "Link a room between Matrix and pnut.io."
|
|
||||||
|
|
||||||
if cmd == 'help':
|
if cmd == 'help':
|
||||||
text = "usage: " + help_usage + "\n\n"
|
text = "usage: " + help_usage + "\n\n"
|
||||||
|
@ -532,7 +510,7 @@ def cmd_admin_help(cmd=None):
|
||||||
|
|
||||||
def cmd_admin_list():
|
def cmd_admin_list():
|
||||||
text = ""
|
text = ""
|
||||||
rooms = Rooms.query.all()
|
rooms = PnutChannels.select()
|
||||||
|
|
||||||
if len(rooms) > 0:
|
if len(rooms) > 0:
|
||||||
text = "ID\tMATRIX ID\tPNUT CHANNEL\n"
|
text = "ID\tMATRIX ID\tPNUT CHANNEL\n"
|
||||||
|
@ -543,108 +521,21 @@ def cmd_admin_list():
|
||||||
text += str(room.id) + '\t'
|
text += str(room.id) + '\t'
|
||||||
text += room.room_id + '\t\t\t\t\t'
|
text += room.room_id + '\t\t\t\t\t'
|
||||||
text += str(room.pnut_chan) + '\t'
|
text += str(room.pnut_chan) + '\t'
|
||||||
if room.portal:
|
|
||||||
text += "(portal)"
|
|
||||||
text += '\n'
|
text += '\n'
|
||||||
|
|
||||||
return TextMessageEventContent(msgtype='m.text', body=text)
|
return TextMessageEventContent(msgtype='m.text', body=text)
|
||||||
|
|
||||||
async def cmd_admin_link(room_id, pnut_chan_id):
|
|
||||||
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
|
||||||
base_url=app.config['MATRIX_HOST'],
|
|
||||||
token=app.config['MATRIX_AS_TOKEN'])
|
|
||||||
pnutpy.api.add_authorization_token(app.config['MATRIX_PNUT_TOKEN'])
|
|
||||||
|
|
||||||
mrcheck = Rooms.query.filter(Rooms.room_id == room_id).one_or_none()
|
|
||||||
pncheck = Rooms.query.filter(Rooms.pnut_chan == pnut_chan_id).one_or_none()
|
|
||||||
|
|
||||||
if mrcheck is not None or pncheck is not None:
|
|
||||||
text = "- room may already be linked -"
|
|
||||||
return TextMessageEventContent(msgtype='m.text', body=text)
|
|
||||||
|
|
||||||
try:
|
|
||||||
channel, meta = pnutpy.api.subscribe_channel(pnut_chan_id)
|
|
||||||
await matrix_api.join_room(room_id)
|
|
||||||
|
|
||||||
rec = Rooms(
|
|
||||||
room_id=room_id,
|
|
||||||
pnut_chan=channel.id,
|
|
||||||
portal=False
|
|
||||||
)
|
|
||||||
db_session.add(rec)
|
|
||||||
db_session.commit()
|
|
||||||
|
|
||||||
except pnutpy.errors.PnutAuthAPIException:
|
|
||||||
errmsg = "- unable to subscribe to channel -"
|
|
||||||
logging.exception(errmsg)
|
|
||||||
return TextMessageEventContent(msgtype='m.text', body=errmsg)
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
errmsg = "- unable to link room for some reason -"
|
|
||||||
logging.exception(errmsg)
|
|
||||||
return TextMessageEventContent(msgtype='m.text', body=errmsg)
|
|
||||||
|
|
||||||
async def cmd_admin_unlink(rid):
|
|
||||||
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
|
||||||
base_url=app.config['MATRIX_HOST'],
|
|
||||||
token=app.config['MATRIX_AS_TOKEN'])
|
|
||||||
pnutpy.api.add_authorization_token(app.config['MATRIX_PNUT_TOKEN'])
|
|
||||||
|
|
||||||
if rid.startswith('!'):
|
|
||||||
room = Rooms.query.filter(Rooms.room_id == rid).one_or_none()
|
|
||||||
else:
|
|
||||||
room = Rooms.query.filter(Rooms.pnut_chan == rid).one_or_none()
|
|
||||||
|
|
||||||
if hasattr(room, 'portal'):
|
|
||||||
if room.portal:
|
|
||||||
alias = "#" + app.config['MATRIX_PNUT_PREFIX']
|
|
||||||
alias += str(room.pnut_chan) + ":"
|
|
||||||
alias += app.config['MATRIX_DOMAIN']
|
|
||||||
await matrix_api.remove_room_alias(alias)
|
|
||||||
|
|
||||||
# Kicking users needs at least moderator privs
|
|
||||||
members = await matrix_api.get_members(room.room_id)
|
|
||||||
reason = "Portal room has been unlinked by administrator"
|
|
||||||
for m in members['chunk']:
|
|
||||||
if (m['content']['membership'] == 'join' and
|
|
||||||
m['sender'] != app.config['MATRIX_AS_ID']):
|
|
||||||
if room.portal:
|
|
||||||
await matrix_api.kick_user(room.room_id,
|
|
||||||
m['sender'],
|
|
||||||
reason=reason)
|
|
||||||
else:
|
|
||||||
prefix = f"@{app.config['MATRIX_PNUT_PREFIX']}"
|
|
||||||
if m['sender'].startswith(prefix):
|
|
||||||
await matrix_api.kick_user(room.room_id,
|
|
||||||
m['sender'],
|
|
||||||
reason=reason)
|
|
||||||
|
|
||||||
try:
|
|
||||||
channel, meta = pnutpy.api.unsubscribe_channel(room.pnut_chan)
|
|
||||||
await matrix_api.leave_room(room.room_id)
|
|
||||||
|
|
||||||
if room is not None:
|
|
||||||
db_session.delete(room)
|
|
||||||
db_session.commit()
|
|
||||||
text = "- room has been unlinked -"
|
|
||||||
else:
|
|
||||||
text = "- unable to locate room to unlink -"
|
|
||||||
|
|
||||||
return TextMessageEventContent(msgtype='m.text', body=text)
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
errmsg = "- error while unlinking room -"
|
|
||||||
logging.exception(errmsg)
|
|
||||||
return TextMessageEventContent(msgtype='m.text', body=errmsg)
|
|
||||||
|
|
||||||
async def on_direct_invite(event):
|
async def on_direct_invite(event):
|
||||||
|
# direct chat with the appservice user
|
||||||
if event['state_key'] == app.config['MATRIX_AS_ID']:
|
if event['state_key'] == app.config['MATRIX_AS_ID']:
|
||||||
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
||||||
base_url=app.config['MATRIX_HOST'],
|
base_url=app.config['MATRIX_HOST'],
|
||||||
token=app.config['MATRIX_AS_TOKEN'])
|
token=app.config['MATRIX_AS_TOKEN'])
|
||||||
dm = ControlRooms(room_id=event['room_id'])
|
|
||||||
|
|
||||||
else:
|
dm = PnutUsers(matrix_id=event['sender'], room_id=event['room_id'])
|
||||||
|
|
||||||
|
# direct chat with another pnut user
|
||||||
|
elif app.config['MATRIX_PNUT_PREFIX'] in event['state_key']:
|
||||||
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
||||||
base_url=app.config['MATRIX_HOST'],
|
base_url=app.config['MATRIX_HOST'],
|
||||||
token=app.config['MATRIX_AS_TOKEN'],
|
token=app.config['MATRIX_AS_TOKEN'],
|
||||||
|
@ -654,62 +545,76 @@ async def on_direct_invite(event):
|
||||||
pnut_user = bridge_user.replace(app.config['MATRIX_PNUT_PREFIX'],
|
pnut_user = bridge_user.replace(app.config['MATRIX_PNUT_PREFIX'],
|
||||||
'').split(':')[0]
|
'').split(':')[0]
|
||||||
|
|
||||||
user = Users.query.filter(Users.matrix_id ==
|
user = PnutUsers.select().where(PnutUsers.matrix_id ==
|
||||||
event['sender']).one_or_none()
|
event['sender']).first()
|
||||||
if user is not None:
|
|
||||||
# TODO: need to handle if the user isn't registered
|
|
||||||
pnutpy.api.add_authorization_token(user.pnut_user_token)
|
|
||||||
channel, meta = pnutpy.api.existing_pm(ids=pnut_user)
|
|
||||||
new_matrix_user(pnut_user)
|
|
||||||
|
|
||||||
dm = DirectRooms(room_id=event['room_id'],
|
if user is not None:
|
||||||
bridge_user=bridge_user, pnut_chan=channel.id)
|
pnutpy.api.add_authorization_token(user.pnut_user_token)
|
||||||
|
|
||||||
|
try:
|
||||||
|
channel, meta = pnutpy.api.existing_pm(ids=pnut_user)
|
||||||
|
new_matrix_user(pnut_user)
|
||||||
|
|
||||||
|
dm = PnutChannels(pnut_chan=channel.id,
|
||||||
|
room_id=event['room_id'],
|
||||||
|
is_direct=True,
|
||||||
|
direct_pnut_user=bridge_user,
|
||||||
|
direct_mtrx_user=user.matrix_id)
|
||||||
|
|
||||||
|
except pnutpy.errors.PnutAuthAPIException:
|
||||||
|
abort(403)
|
||||||
|
|
||||||
|
else:
|
||||||
|
abort(403)
|
||||||
|
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logging.debug('--> trying to join room <--')
|
logging.debug('--> trying to join room <--')
|
||||||
await matrix_api.join_room_by_id(event['room_id'])
|
await matrix_api.join_room_by_id(event['room_id'])
|
||||||
|
dm.save()
|
||||||
db_session.add(dm)
|
|
||||||
db_session.commit()
|
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
errmsg = "- on_direct_invite -"
|
errmsg = "- on_direct_invite -"
|
||||||
logging.exception(errmsg)
|
logging.exception(errmsg)
|
||||||
|
|
||||||
async def on_leave_event(event):
|
async def on_leave_event(event):
|
||||||
direct = DirectRooms.query.filter(DirectRooms.room_id ==
|
direct_room = PnutChannels.select().where(PnutChannels.room_id ==
|
||||||
event['room_id']).one_or_none()
|
event['room_id']).first()
|
||||||
if direct is not None:
|
|
||||||
|
user = PnutUsers.select().where(PnutUsers.room_id ==
|
||||||
|
event['room_id']).first()
|
||||||
|
|
||||||
|
if direct_room is not None:
|
||||||
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
||||||
base_url=app.config['MATRIX_HOST'],
|
base_url=app.config['MATRIX_HOST'],
|
||||||
token=app.config['MATRIX_AS_TOKEN'],
|
token=app.config['MATRIX_AS_TOKEN'],
|
||||||
as_user_id=direct.bridge_user.lower())
|
as_user_id=direct_room.direct_pnut_user.lower())
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await matrix_api.leave_room(event['room_id'])
|
await matrix_api.leave_room(event['room_id'])
|
||||||
db_session.delete(direct)
|
direct_room.delete_instance()
|
||||||
db_session.commit()
|
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
errmsg = "- on_leave_event -"
|
errmsg = "- on_leave_event -"
|
||||||
logging.exception(errmsg)
|
logging.exception(errmsg)
|
||||||
|
|
||||||
control = ControlRooms.query.filter(ControlRooms.room_id ==
|
if user is not None:
|
||||||
event['room_id']).one_or_none()
|
|
||||||
if control is not None:
|
|
||||||
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
||||||
base_url=app.config['MATRIX_HOST'],
|
base_url=app.config['MATRIX_HOST'],
|
||||||
token=app.config['MATRIX_AS_TOKEN'])
|
token=app.config['MATRIX_AS_TOKEN'])
|
||||||
try:
|
try:
|
||||||
await matrix_api.leave_room(event['room_id'])
|
await matrix_api.leave_room(event['room_id'])
|
||||||
db_session.delete(control)
|
user.room_id = None
|
||||||
db_session.commit()
|
user.save()
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
errmsg = "- on_leave_event -"
|
errmsg = "- on_leave_event -"
|
||||||
logging.exception(errmsg)
|
logging.exception(errmsg)
|
||||||
|
|
||||||
def on_direct_message(event, user, room):
|
def on_direct_message(event, user, room):
|
||||||
|
|
||||||
if user is not None:
|
if user is not None:
|
||||||
token = user.pnut_user_token
|
token = user.pnut_user_token
|
||||||
prefix = ""
|
prefix = ""
|
||||||
|
@ -727,19 +632,17 @@ def on_direct_message(event, user, room):
|
||||||
raw['io.pnut.core.crosspost'] = [crosspost_raw(event)]
|
raw['io.pnut.core.crosspost'] = [crosspost_raw(event)]
|
||||||
evtext, evraw = msg_from_event(event)
|
evtext, evraw = msg_from_event(event)
|
||||||
text = prefix + evtext
|
text = prefix + evtext
|
||||||
|
|
||||||
try:
|
try:
|
||||||
msg, meta = pnutpy.api.create_message(room.pnut_chan,
|
msg, meta = pnutpy.api.create_message(room.pnut_chan,
|
||||||
data={'text': text, 'raw': raw})
|
data={'text': text, 'raw': raw})
|
||||||
revent = Events(
|
bridge_event = Events(
|
||||||
event_id=event['event_id'],
|
event_id=event['event_id'],
|
||||||
room_id=event['room_id'],
|
room_id=event['room_id'],
|
||||||
pnut_msg_id=msg.id,
|
pnut_id=msg.id,
|
||||||
pnut_user_id=msg.user.id,
|
pnut_channel=room.pnut_chan
|
||||||
pnut_chan_id=room.pnut_chan,
|
|
||||||
deleted=False
|
|
||||||
)
|
)
|
||||||
db_session.add(revent)
|
bridge_event.save()
|
||||||
db_session.commit()
|
|
||||||
|
|
||||||
except pnutpy.errors.PnutAuthAPIException:
|
except pnutpy.errors.PnutAuthAPIException:
|
||||||
logging.exception('-unable to post to pnut channel-')
|
logging.exception('-unable to post to pnut channel-')
|
||||||
|
@ -749,11 +652,10 @@ def on_direct_message(event, user, room):
|
||||||
|
|
||||||
return jsonify({})
|
return jsonify({})
|
||||||
|
|
||||||
async def on_control_message(event):
|
async def on_control_message(event, user):
|
||||||
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
||||||
base_url=app.config['MATRIX_HOST'],
|
base_url=app.config['MATRIX_HOST'],
|
||||||
token=app.config['MATRIX_AS_TOKEN'])
|
token=app.config['MATRIX_AS_TOKEN'])
|
||||||
logging.debug("- direct room event received -")
|
|
||||||
|
|
||||||
if event['type'] != 'm.room.message':
|
if event['type'] != 'm.room.message':
|
||||||
return jsonify({})
|
return jsonify({})
|
||||||
|
@ -775,26 +677,25 @@ async def on_control_message(event):
|
||||||
elif msg[0] == '!save':
|
elif msg[0] == '!save':
|
||||||
if len(msg) > 1:
|
if len(msg) > 1:
|
||||||
await matrix_api.send_message(event['room_id'],
|
await matrix_api.send_message(event['room_id'],
|
||||||
cmd_user_save(event['sender'],
|
cmd_user_save(user, msg[1]))
|
||||||
msg[1]))
|
|
||||||
else:
|
else:
|
||||||
await matrix_api.send_message(event['room_id'],
|
await matrix_api.send_message(event['room_id'],
|
||||||
cmd_user_save())
|
cmd_user_save())
|
||||||
|
|
||||||
elif msg[0] == '!drop':
|
elif msg[0] == '!drop':
|
||||||
await matrix_api.send_message(event['room_id'],
|
r = await cmd_user_drop(user)
|
||||||
cmd_user_drop(event['sender']))
|
await matrix_api.send_message(event['room_id'], r)
|
||||||
|
|
||||||
elif msg[0] == '!status':
|
elif msg[0] == '!status':
|
||||||
await matrix_api.send_message(event['room_id'],
|
await matrix_api.send_message(event['room_id'],
|
||||||
cmd_user_status(event['sender']))
|
cmd_user_status(user))
|
||||||
|
|
||||||
elif msg[0] == '!join':
|
elif msg[0] == '!join':
|
||||||
if len(msg) > 1:
|
if len(msg) > 1:
|
||||||
r = await cmd_user_join(event['sender'], msg[1])
|
r = await cmd_user_join(user, msg[1])
|
||||||
await matrix_api.send_message(event['room_id'], r)
|
await matrix_api.send_message(event['room_id'], r)
|
||||||
else:
|
else:
|
||||||
r = await cmd_user_join(event['sender'])
|
r = await cmd_user_join(user)
|
||||||
await matrix_api.send_message(event['room_id'], r)
|
await matrix_api.send_message(event['room_id'], r)
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -822,7 +723,7 @@ def cmd_user_auth():
|
||||||
|
|
||||||
return TextMessageEventContent(msgtype='m.text', body=reply)
|
return TextMessageEventContent(msgtype='m.text', body=reply)
|
||||||
|
|
||||||
def cmd_user_save(sender=None, token=None):
|
def cmd_user_save(user, token=None):
|
||||||
if token is None:
|
if token is None:
|
||||||
reply = "You must provide a token with this command.\n"
|
reply = "You must provide a token with this command.\n"
|
||||||
reply += "!save <token>"
|
reply += "!save <token>"
|
||||||
|
@ -832,13 +733,9 @@ def cmd_user_save(sender=None, token=None):
|
||||||
try:
|
try:
|
||||||
response, meta = pnutpy.api.get_user('me')
|
response, meta = pnutpy.api.get_user('me')
|
||||||
|
|
||||||
user = Users(
|
user.pnut_user_id = response.id
|
||||||
matrix_id=sender,
|
user.pnut_user_token = token
|
||||||
pnut_user_id=response.id,
|
user.save()
|
||||||
pnut_user_token=token
|
|
||||||
)
|
|
||||||
db_session.add(user)
|
|
||||||
db_session.commit()
|
|
||||||
|
|
||||||
reply = "Success! You are now authorized as " + response['username']
|
reply = "Success! You are now authorized as " + response['username']
|
||||||
|
|
||||||
|
@ -851,25 +748,37 @@ def cmd_user_save(sender=None, token=None):
|
||||||
|
|
||||||
return TextMessageEventContent(msgtype='m.text', body=reply)
|
return TextMessageEventContent(msgtype='m.text', body=reply)
|
||||||
|
|
||||||
def cmd_user_drop(sender=None):
|
async def cmd_user_drop(user):
|
||||||
try:
|
|
||||||
user = Users.query.filter(Users.matrix_id == sender).one_or_none()
|
|
||||||
if user is not None:
|
|
||||||
db_session.delete(user)
|
|
||||||
db_session.commit()
|
|
||||||
reply = "Success! Your auth token has been removed."
|
|
||||||
else:
|
|
||||||
reply = "You do not appear to be registered."
|
|
||||||
|
|
||||||
except Exception as e:
|
direct_rooms = PnutChannels.select().where(PnutChannels.direct_mtrx_user ==
|
||||||
logging.exception('!drop')
|
user.matrix_id)
|
||||||
reply = "Error! Problem removing your token."
|
for dir_room in direct_rooms:
|
||||||
|
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
||||||
|
base_url=app.config['MATRIX_HOST'],
|
||||||
|
token=app.config['MATRIX_AS_TOKEN'],
|
||||||
|
as_user_id=dir_room.direct_pnut_user.lower())
|
||||||
|
await matrix_api.leave_room(dir_room.room_id)
|
||||||
|
dir_room.delete_instance()
|
||||||
|
|
||||||
|
private_rooms = PnutPrivateChanMembers.select().where(
|
||||||
|
PnutPrivateChanMembers.pnut_user_id == user.pnut_user_id)
|
||||||
|
for priv_room in private_rooms:
|
||||||
|
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
||||||
|
base_url=app.config['MATRIX_HOST'],
|
||||||
|
token=app.config['MATRIX_AS_TOKEN'])
|
||||||
|
await matrix_api.kick_user(priv_room.room_id, user.matrix_id,
|
||||||
|
reason='user left from bridge')
|
||||||
|
priv_room.delete_instance()
|
||||||
|
|
||||||
|
user.pnut_user_id = None
|
||||||
|
user.pnut_user_token = None
|
||||||
|
user.save()
|
||||||
|
reply = "Success! Your auth token has been removed."
|
||||||
|
|
||||||
return TextMessageEventContent(msgtype='m.text', body=reply)
|
return TextMessageEventContent(msgtype='m.text', body=reply)
|
||||||
|
|
||||||
def cmd_user_status(sender=None):
|
def cmd_user_status(user):
|
||||||
try:
|
try:
|
||||||
user = Users.query.filter(Users.matrix_id == sender).one_or_none()
|
|
||||||
if user is None:
|
if user is None:
|
||||||
reply = "You are currently not authorized on pnut.io"
|
reply = "You are currently not authorized on pnut.io"
|
||||||
else:
|
else:
|
||||||
|
@ -886,28 +795,27 @@ def cmd_user_status(sender=None):
|
||||||
|
|
||||||
return TextMessageEventContent(msgtype='m.text', body=reply)
|
return TextMessageEventContent(msgtype='m.text', body=reply)
|
||||||
|
|
||||||
async def cmd_user_join(sender=None, channel_id=None):
|
async def cmd_user_join(user, channel_id=None):
|
||||||
if channel_id is None:
|
if channel_id is None:
|
||||||
reply = "You must provide a channel id number with this command.\n"
|
reply = "You must provide a channel id number with this command.\n"
|
||||||
reply += "!join <channel #>"
|
reply += "!join <channel #>"
|
||||||
return TextMessageEventContent(msgtype='m.text', body=reply)
|
return TextMessageEventContent(msgtype='m.text', body=reply)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
user = Users.query.filter(Users.matrix_id == sender).one_or_none()
|
|
||||||
if user is None:
|
if user is None:
|
||||||
reply = "You are currently not authorized on pnut.io"
|
reply = "You are currently not authorized on pnut.io"
|
||||||
else:
|
else:
|
||||||
pnutpy.api.add_authorization_token(user.pnut_user_token)
|
pnutpy.api.add_authorization_token(user.pnut_user_token)
|
||||||
channel, meta = pnutpy.api.get_channel(channel_id, include_raw=1)
|
channel, meta = pnutpy.api.get_channel(channel_id, include_raw=1)
|
||||||
room = Rooms.query.filter(Rooms.pnut_chan ==
|
room = PnutChannels.select().where(PnutChannels.pnut_chan ==
|
||||||
channel_id).one_or_none()
|
channel_id).first()
|
||||||
if room is None:
|
if room is None:
|
||||||
await create_pnut_matrix_room(channel, user)
|
await create_pnut_matrix_room(channel, user)
|
||||||
else:
|
else:
|
||||||
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
||||||
base_url=app.config['MATRIX_HOST'],
|
base_url=app.config['MATRIX_HOST'],
|
||||||
token=app.config['MATRIX_AS_TOKEN'])
|
token=app.config['MATRIX_AS_TOKEN'])
|
||||||
await matrix_api.invite_user(room.room_id, sender)
|
await matrix_api.invite_user(room.room_id, user.matrix_id)
|
||||||
reply = "ok"
|
reply = "ok"
|
||||||
|
|
||||||
except pnutpy.errors.PnutAuthAPIException as e:
|
except pnutpy.errors.PnutAuthAPIException as e:
|
||||||
|
@ -952,6 +860,10 @@ def main():
|
||||||
|
|
||||||
app.config.update(config)
|
app.config.update(config)
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
|
||||||
|
db.init(config['SERVICE_DB'])
|
||||||
|
db_create_tables()
|
||||||
|
|
||||||
app.run(host=config['LISTEN_HOST'], port=config['LISTEN_PORT'])
|
app.run(host=config['LISTEN_HOST'], port=config['LISTEN_PORT'])
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
from sqlalchemy import create_engine
|
|
||||||
from sqlalchemy.orm import scoped_session, sessionmaker
|
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
|
||||||
import yaml
|
|
||||||
import os
|
|
||||||
|
|
||||||
configyaml = os.environ.get("CONFIG_FILE")
|
|
||||||
|
|
||||||
with open(configyaml, "rb") as config_file:
|
|
||||||
config = yaml.load(config_file, Loader=yaml.SafeLoader)
|
|
||||||
|
|
||||||
engine = create_engine(config['SERVICE_DB'])
|
|
||||||
db_session = scoped_session(sessionmaker(bind=engine))
|
|
||||||
|
|
||||||
Base = declarative_base()
|
|
||||||
|
|
||||||
Base.query = db_session.query_property()
|
|
||||||
|
|
||||||
def init_db():
|
|
||||||
# import all modules here that might define models so that
|
|
||||||
# they will be registered properly on the metadata. Otherwise
|
|
||||||
# you will have to import them first before calling init_db()
|
|
||||||
import pnut_matrix.models
|
|
||||||
Base.metadata.create_all(bind=engine)
|
|
|
@ -1,44 +1,48 @@
|
||||||
from sqlalchemy import Column, ForeignKey, Integer, String, Boolean
|
import logging
|
||||||
from pnut_matrix.database import Base
|
|
||||||
|
|
||||||
class Avatars(Base):
|
from peewee import *
|
||||||
__tablename__ = 'avatars'
|
from playhouse.migrate import *
|
||||||
id = Column(Integer, primary_key=True)
|
|
||||||
pnut_user = Column(String(250), unique=True)
|
|
||||||
avatar = Column(String(250))
|
|
||||||
|
|
||||||
class Rooms(Base):
|
db = SqliteDatabase(None)
|
||||||
__tablename__ = 'rooms'
|
migrator = SqliteMigrator(db)
|
||||||
id = Column(Integer, primary_key=True)
|
|
||||||
room_id = Column(String(250), unique=True)
|
|
||||||
pnut_chan = Column(Integer, unique=True)
|
|
||||||
portal = Column(Boolean)
|
|
||||||
|
|
||||||
class DirectRooms(Base):
|
class BaseModel(Model):
|
||||||
__tablename__ = 'direct'
|
class Meta:
|
||||||
id = Column(Integer, primary_key=True)
|
database = db
|
||||||
room_id = Column(String(250), unique=True)
|
|
||||||
pnut_chan = Column(Integer, unique=True)
|
|
||||||
bridge_user = Column(String(250))
|
|
||||||
|
|
||||||
class ControlRooms(Base):
|
class PnutAvatars(BaseModel):
|
||||||
__tablename__ = 'control'
|
pnut_user = CharField(unique=True)
|
||||||
id = Column(Integer, primary_key=True)
|
avatar_url = CharField()
|
||||||
room_id = Column(String(250), unique=True)
|
|
||||||
|
|
||||||
class Events(Base):
|
class PnutChannels(BaseModel):
|
||||||
__tablename__ = 'events'
|
pnut_chan = IntegerField(unique=True)
|
||||||
id = Column(Integer, primary_key=True)
|
room_id = CharField()
|
||||||
event_id = Column(String(250))
|
is_private = BooleanField(default=False)
|
||||||
room_id = Column(String(250))
|
is_direct = BooleanField(default=False)
|
||||||
pnut_msg_id = Column(Integer)
|
direct_pnut_user = CharField(null=True)
|
||||||
pnut_user_id = Column(Integer)
|
direct_mtrx_user = CharField(null=True)
|
||||||
pnut_chan_id = Column(Integer)
|
|
||||||
deleted = Column(Boolean)
|
|
||||||
|
|
||||||
class Users(Base):
|
class PnutPrivateChanMembers(BaseModel):
|
||||||
__tablename__ = 'users'
|
pnut_chan = IntegerField()
|
||||||
id = Column(Integer, primary_key=True)
|
room_id = CharField()
|
||||||
matrix_id = Column(String(250))
|
pnut_user_id = IntegerField()
|
||||||
pnut_user_id = Column(Integer)
|
matrix_id = CharField()
|
||||||
pnut_user_token = Column(String(250))
|
|
||||||
|
class Events(BaseModel):
|
||||||
|
event_id = CharField(unique=True)
|
||||||
|
room_id = CharField()
|
||||||
|
pnut_id = IntegerField()
|
||||||
|
pnut_channel = IntegerField()
|
||||||
|
revised = BooleanField(default=False)
|
||||||
|
deleted = BooleanField(default=False)
|
||||||
|
|
||||||
|
class PnutUsers(BaseModel):
|
||||||
|
matrix_id = CharField(unique=True)
|
||||||
|
room_id = CharField()
|
||||||
|
pnut_user_id = IntegerField(unique=True, null=True)
|
||||||
|
pnut_user_token = CharField(null=True)
|
||||||
|
|
||||||
|
def db_create_tables():
|
||||||
|
with db:
|
||||||
|
db.create_tables([PnutUsers, Events, PnutChannels, PnutAvatars,
|
||||||
|
PnutPrivateChanMembers])
|
||||||
|
|
|
@ -19,13 +19,13 @@ from mautrix.errors.request import MNotFound, MForbidden
|
||||||
from websockets.asyncio.client import connect
|
from websockets.asyncio.client import connect
|
||||||
from websockets.exceptions import ConnectionClosed
|
from websockets.exceptions import ConnectionClosed
|
||||||
|
|
||||||
from pnut_matrix.models import Avatars, Rooms, Events, DirectRooms, Users
|
from pnut_matrix.models import *
|
||||||
from pnut_matrix.database import db_session, init_db
|
|
||||||
from sqlalchemy import and_
|
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
config = None
|
config = None
|
||||||
|
matrix_url = None
|
||||||
|
|
||||||
class MLogFilter(logging.Filter):
|
class MLogFilter(logging.Filter):
|
||||||
|
|
||||||
|
@ -64,12 +64,11 @@ async def new_pnut_message(msg, meta):
|
||||||
token=config['MATRIX_AS_TOKEN'],
|
token=config['MATRIX_AS_TOKEN'],
|
||||||
as_user_id=matrix_id.lower())
|
as_user_id=matrix_id.lower())
|
||||||
|
|
||||||
if meta['channel_type'] == 'io.pnut.core.chat':
|
channel_id = int(msg.channel_id)
|
||||||
room = Rooms.query.filter(Rooms.pnut_chan ==
|
room = PnutChannels.select().where(PnutChannels.pnut_chan ==
|
||||||
msg.channel_id).one_or_none()
|
channel_id).first()
|
||||||
elif meta['channel_type'] == 'io.pnut.core.pm':
|
|
||||||
room = DirectRooms.query.filter(DirectRooms.pnut_chan ==
|
if meta['channel_type'] == 'io.pnut.core.pm':
|
||||||
msg.channel_id).one_or_none()
|
|
||||||
if room is None:
|
if room is None:
|
||||||
# Do do an invite from the bridge user?
|
# Do do an invite from the bridge user?
|
||||||
logger.debug('new invite?')
|
logger.debug('new invite?')
|
||||||
|
@ -77,21 +76,22 @@ async def new_pnut_message(msg, meta):
|
||||||
# subscribed_user_ids from meta
|
# subscribed_user_ids from meta
|
||||||
logger.debug(meta['subscribed_user_ids'])
|
logger.debug(meta['subscribed_user_ids'])
|
||||||
pnut_user = matrix_id_from_pnut(msg.user.username)
|
pnut_user = matrix_id_from_pnut(msg.user.username)
|
||||||
profile = await matrix_api.get_profile(matrix_id.lower())
|
try:
|
||||||
if not profile:
|
profile = await matrix_api.get_profile(matrix_id.lower())
|
||||||
|
|
||||||
|
except MNotFound:
|
||||||
new_matrix_user(msg.user.username)
|
new_matrix_user(msg.user.username)
|
||||||
|
|
||||||
invitees=[]
|
invitees=[]
|
||||||
for pm_user in meta['subscribed_user_ids']:
|
for pm_user in meta['subscribed_user_ids']:
|
||||||
user = Users.query.filter(Users.pnut_user_id ==
|
user = PnutUsers.select().where(PnutUsers.pnut_user_id ==
|
||||||
pm_user).one_or_none()
|
pm_user).first()
|
||||||
if int(pm_user) == msg.user.id:
|
if int(pm_user) == msg.user.id:
|
||||||
continue
|
continue
|
||||||
if user is not None:
|
if user is not None:
|
||||||
invitees.append(user.matrix_id)
|
invitees.append(user.matrix_id)
|
||||||
if len(invitees) > 0:
|
if len(invitees) > 0:
|
||||||
room = new_room(pnut_user, invitees, msg.channel_id)
|
room = new_room(pnut_user, invitees, msg.channel_id)
|
||||||
else:
|
|
||||||
room = None
|
|
||||||
|
|
||||||
logger.debug(room)
|
logger.debug(room)
|
||||||
if room is None:
|
if room is None:
|
||||||
|
@ -111,17 +111,19 @@ async def new_pnut_message(msg, meta):
|
||||||
await set_matrix_display(msg.user)
|
await set_matrix_display(msg.user)
|
||||||
logger.debug('-set_display-')
|
logger.debug('-set_display-')
|
||||||
|
|
||||||
avatar = Avatars.query.filter(Avatars.pnut_user ==
|
avatar = PnutAvatars.select().where(PnutAvatars.pnut_user ==
|
||||||
msg.user.username).one_or_none()
|
msg.user.username).first()
|
||||||
if avatar is None or avatar.avatar != msg.user.content.avatar_image.url:
|
if avatar is None or avatar.avatar_url != msg.user.content.avatar_image.url:
|
||||||
await set_matrix_avatar(msg.user)
|
await set_matrix_avatar(msg.user)
|
||||||
logger.debug('-set_avatar-')
|
logger.debug('-set_avatar-')
|
||||||
|
|
||||||
# members = matrix_api.get_room_members(room.room_id)
|
if room.is_private:
|
||||||
# logger.debug(members)
|
matrix_api_as = ClientAPI(config['MATRIX_AS_ID'],
|
||||||
# join_room(room.room_id, config['MATRIX_AS_ID'])
|
base_url=config['MATRIX_HOST'],
|
||||||
# TODO: sort out room invite and join logic
|
token=config['MATRIX_AS_TOKEN'])
|
||||||
await join_room(room.room_id, matrix_id)
|
await matrix_api_as.invite_user(room.room_id, matrix_id.lower())
|
||||||
|
|
||||||
|
await matrix_api.join_room(room.room_id)
|
||||||
|
|
||||||
if 'content' in msg:
|
if 'content' in msg:
|
||||||
eventtext = TextMessageEventContent(msgtype=MessageType.TEXT,
|
eventtext = TextMessageEventContent(msgtype=MessageType.TEXT,
|
||||||
|
@ -129,15 +131,13 @@ async def new_pnut_message(msg, meta):
|
||||||
body=msg.content.text,
|
body=msg.content.text,
|
||||||
formatted_body=msg.content.html)
|
formatted_body=msg.content.html)
|
||||||
rid = await matrix_api.send_message(room.room_id, eventtext)
|
rid = await matrix_api.send_message(room.room_id, eventtext)
|
||||||
event = Events(
|
bridge_event = Events(
|
||||||
event_id=rid,
|
event_id=rid,
|
||||||
room_id=room.room_id,
|
room_id=room.room_id,
|
||||||
pnut_msg_id=msg.id,
|
pnut_id=msg.id,
|
||||||
pnut_user_id=msg.user.id,
|
pnut_channel=msg.channel_id
|
||||||
pnut_chan_id=msg.channel_id,
|
)
|
||||||
deleted=False)
|
bridge_event.save()
|
||||||
db_session.add(event)
|
|
||||||
db_session.commit()
|
|
||||||
|
|
||||||
if 'raw' in msg:
|
if 'raw' in msg:
|
||||||
logger.debug('-handle media uploads-')
|
logger.debug('-handle media uploads-')
|
||||||
|
@ -177,15 +177,15 @@ async def new_pnut_post(post, meta):
|
||||||
await set_matrix_display(post.user)
|
await set_matrix_display(post.user)
|
||||||
logger.debug('-set_display-')
|
logger.debug('-set_display-')
|
||||||
|
|
||||||
avatar = Avatars.query.filter(Avatars.pnut_user ==
|
avatar = PnutAvatars.select().where(PnutAvatars.pnut_user ==
|
||||||
post.user.username).one_or_none()
|
post.user.username).first()
|
||||||
if (avatar is None or
|
if (avatar is None or
|
||||||
avatar.avatar != post.user.content.avatar_image.url):
|
avatar.avatar_url != post.user.content.avatar_image.url):
|
||||||
await set_matrix_avatar(post.user)
|
await set_matrix_avatar(post.user)
|
||||||
logger.debug('-set_avatar-')
|
logger.debug('-set_avatar-')
|
||||||
|
|
||||||
room_id = config['MATRIX_GLOBAL_ROOM']
|
room_id = config['MATRIX_GLOBAL_ROOM']
|
||||||
await join_room(room_id, matrix_id)
|
await matrix_api.join_room(room_id)
|
||||||
postlink = f"https://posts.pnut.io/{post.id}"
|
postlink = f"https://posts.pnut.io/{post.id}"
|
||||||
plaintext = f"{post.content.text}\n{postlink}"
|
plaintext = f"{post.content.text}\n{postlink}"
|
||||||
htmltext = (f"{post.content.html}"
|
htmltext = (f"{post.content.html}"
|
||||||
|
@ -195,15 +195,13 @@ async def new_pnut_post(post, meta):
|
||||||
body=plaintext,
|
body=plaintext,
|
||||||
formatted_body=htmltext)
|
formatted_body=htmltext)
|
||||||
rid = await matrix_api.send_message(room_id, eventtext)
|
rid = await matrix_api.send_message(room_id, eventtext)
|
||||||
event = Events(
|
bridge_event = Events(
|
||||||
event_id=rid,
|
event_id=rid,
|
||||||
room_id=room_id,
|
room_id=room_id,
|
||||||
pnut_msg_id=post.id,
|
pnut_id=post.id,
|
||||||
pnut_user_id=post.user.id,
|
pnut_channel=0
|
||||||
pnut_chan_id=0,
|
)
|
||||||
deleted=False)
|
bridge_event.save()
|
||||||
db_session.add(event)
|
|
||||||
db_session.commit()
|
|
||||||
|
|
||||||
if 'raw' in post:
|
if 'raw' in post:
|
||||||
logger.debug('-handle media uploads-')
|
logger.debug('-handle media uploads-')
|
||||||
|
@ -231,7 +229,7 @@ async def new_media(room_id, msg):
|
||||||
dl_url = oembed.url
|
dl_url = oembed.url
|
||||||
elif oembed.type == 'video':
|
elif oembed.type == 'video':
|
||||||
msgtype = 'm.video'
|
msgtype = 'm.video'
|
||||||
dl_url = oembed.url
|
dl_url = oembed.embeddable_url
|
||||||
info['h'] = oembed.height
|
info['h'] = oembed.height
|
||||||
info['w'] = oembed.width
|
info['w'] = oembed.width
|
||||||
elif oembed.type == 'html5video':
|
elif oembed.type == 'html5video':
|
||||||
|
@ -267,15 +265,13 @@ async def new_media(room_id, msg):
|
||||||
channel_id = msg.channel_id
|
channel_id = msg.channel_id
|
||||||
else:
|
else:
|
||||||
channel_id = 0
|
channel_id = 0
|
||||||
event = Events(
|
bridge_event = Events(
|
||||||
event_id=rid,
|
event_id=rid,
|
||||||
room_id=room_id,
|
room_id=room_id,
|
||||||
pnut_msg_id=msg.id,
|
pnut_id=msg.id,
|
||||||
pnut_user_id=msg.user.id,
|
pnut_channel=channel_id
|
||||||
pnut_chan_id=channel_id,
|
)
|
||||||
deleted=False)
|
bridge_event.save()
|
||||||
db_session.add(event)
|
|
||||||
db_session.commit()
|
|
||||||
|
|
||||||
async def delete_message(msg):
|
async def delete_message(msg):
|
||||||
matrix_id = matrix_id_from_pnut(msg.user.username)
|
matrix_id = matrix_id_from_pnut(msg.user.username)
|
||||||
|
@ -284,12 +280,12 @@ async def delete_message(msg):
|
||||||
token=config['MATRIX_AS_TOKEN'],
|
token=config['MATRIX_AS_TOKEN'],
|
||||||
as_user_id=matrix_id.lower())
|
as_user_id=matrix_id.lower())
|
||||||
|
|
||||||
events = Events.query.filter(and_(Events.pnut_msg_id ==
|
events = Events.select().where((Events.pnut_id == msg.id) &
|
||||||
msg.id, Events.deleted == False)).all()
|
(Events.deleted == False))
|
||||||
for event in events:
|
for event in events:
|
||||||
await matrix_api.redact(event.room_id, event.event_id)
|
await matrix_api.redact(event.room_id, event.event_id)
|
||||||
event.deleted = True
|
event.deleted = True
|
||||||
db_session.commit()
|
event.save()
|
||||||
|
|
||||||
def matrix_id_from_pnut(username):
|
def matrix_id_from_pnut(username):
|
||||||
matrix_id = (f"@{config['MATRIX_PNUT_PREFIX']}{username}"
|
matrix_id = (f"@{config['MATRIX_PNUT_PREFIX']}{username}"
|
||||||
|
@ -334,15 +330,17 @@ async def set_matrix_avatar(user):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await matrix_api.set_avatar_url(ul)
|
await matrix_api.set_avatar_url(ul)
|
||||||
avatar = Avatars.query.filter(Avatars.pnut_user ==
|
|
||||||
user.username).one_or_none()
|
avatar = PnutAvatars.select().where(PnutAvatars.pnut_user ==
|
||||||
|
user.username).first()
|
||||||
if avatar is None:
|
if avatar is None:
|
||||||
avatar = Avatars(pnut_user=user.username,
|
avatar = PnutAvatars(pnut_user=user.username,
|
||||||
avatar=user.content.avatar_image.url)
|
avatar_url=user.content.avatar_image.url)
|
||||||
db_session.add(avatar)
|
|
||||||
else:
|
else:
|
||||||
avatar.avatar = user.content.avatar_image.url
|
avatar.avatar_url = user.content.avatar_image.url
|
||||||
db_session.commit()
|
|
||||||
|
avatar.save()
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception('failed to set user avatar')
|
logger.exception('failed to set user avatar')
|
||||||
|
@ -371,39 +369,6 @@ def new_matrix_user(username):
|
||||||
logger.debug(r.text)
|
logger.debug(r.text)
|
||||||
return
|
return
|
||||||
|
|
||||||
async def join_room(room_id, matrix_id):
|
|
||||||
logging.debug('----- trying to join room -----')
|
|
||||||
|
|
||||||
matrix_api_as = ClientAPI(config['MATRIX_AS_ID'],
|
|
||||||
base_url=config['MATRIX_HOST'],
|
|
||||||
token=config['MATRIX_AS_TOKEN'])
|
|
||||||
|
|
||||||
matrix_api = ClientAPI(config['MATRIX_AS_ID'],
|
|
||||||
base_url=config['MATRIX_HOST'],
|
|
||||||
token=config['MATRIX_AS_TOKEN'],
|
|
||||||
as_user_id=matrix_id.lower())
|
|
||||||
|
|
||||||
try:
|
|
||||||
await matrix_api.join_room(room_id)
|
|
||||||
# logging.debug('----- should be joined -----')
|
|
||||||
|
|
||||||
except MForbidden:
|
|
||||||
# logging.debug('------ got a forbidden ------')
|
|
||||||
await matrix_api_as.invite_user(room_id, matrix_id.lower())
|
|
||||||
await matrix_api.join_room(room_id)
|
|
||||||
|
|
||||||
except MatrixConnectionError:
|
|
||||||
# logger.debug(e)
|
|
||||||
# if 'code' in e and e.code == 403:
|
|
||||||
# await matrix_api_as.invite_user(room_id, matrix_id)
|
|
||||||
# await matrix_api.join_room(room_id)
|
|
||||||
# else:
|
|
||||||
logging.debug('------- moar join errors -------')
|
|
||||||
logger.exception('failed to join room')
|
|
||||||
logger.debug(f"{room_id}")
|
|
||||||
|
|
||||||
logger.debug('-room_join-')
|
|
||||||
|
|
||||||
def new_room(pnut_user, invitees, chan):
|
def new_room(pnut_user, invitees, chan):
|
||||||
dr = None
|
dr = None
|
||||||
url = matrix_url + '/createRoom'
|
url = matrix_url + '/createRoom'
|
||||||
|
@ -424,13 +389,11 @@ def new_room(pnut_user, invitees, chan):
|
||||||
logger.debug(r.text)
|
logger.debug(r.text)
|
||||||
logger.debug(response)
|
logger.debug(response)
|
||||||
for bridge_user in invitees:
|
for bridge_user in invitees:
|
||||||
dr = DirectRooms(room_id=response['room_id'],
|
direct_room = PnutChannels(pnut_chan=chan, room_id=response['room_id'],
|
||||||
bridge_user=pnut_user, pnut_chan=chan)
|
is_direct=True, direct_pnut_user=pnut_user,
|
||||||
logger.debug(dr)
|
direct_mtrx_user=bridge_user)
|
||||||
db_session.add(dr)
|
direct_room.save()
|
||||||
db_session.commit()
|
return direct_room
|
||||||
|
|
||||||
return dr
|
|
||||||
|
|
||||||
async def on_message(message):
|
async def on_message(message):
|
||||||
logger.debug("on_message: " + message)
|
logger.debug("on_message: " + message)
|
||||||
|
@ -473,7 +436,10 @@ async def on_message(message):
|
||||||
async def asmain():
|
async def asmain():
|
||||||
if config['MATRIX_ADMIN_ROOM']:
|
if config['MATRIX_ADMIN_ROOM']:
|
||||||
logger.debug("- sould join admin room -")
|
logger.debug("- sould join admin room -")
|
||||||
await join_room(config['MATRIX_ADMIN_ROOM'], config['MATRIX_AS_ID'])
|
matrix_api_as = ClientAPI(config['MATRIX_AS_ID'],
|
||||||
|
base_url=config['MATRIX_HOST'],
|
||||||
|
token=config['MATRIX_AS_TOKEN'])
|
||||||
|
await matrix_api_as.join_room(config['MATRIX_ADMIN_ROOM'])
|
||||||
|
|
||||||
ws_url = 'wss://stream.pnut.io/v1/app?access_token='
|
ws_url = 'wss://stream.pnut.io/v1/app?access_token='
|
||||||
ws_url += config['PNUT_APPTOKEN'] + '&key=' + config['PNUT_APPKEY']
|
ws_url += config['PNUT_APPTOKEN'] + '&key=' + config['PNUT_APPKEY']
|
||||||
|
@ -490,6 +456,7 @@ async def asmain():
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
global config
|
global config
|
||||||
|
global matrix_url
|
||||||
a_parser = argparse.ArgumentParser()
|
a_parser = argparse.ArgumentParser()
|
||||||
a_parser.add_argument(
|
a_parser.add_argument(
|
||||||
'-d', action='store_true', dest='debug',
|
'-d', action='store_true', dest='debug',
|
||||||
|
@ -504,6 +471,9 @@ def main():
|
||||||
with open(configyaml, "rb") as config_file:
|
with open(configyaml, "rb") as config_file:
|
||||||
config = yaml.load(config_file, Loader=yaml.SafeLoader)
|
config = yaml.load(config_file, Loader=yaml.SafeLoader)
|
||||||
|
|
||||||
|
db.init(config['SERVICE_DB'])
|
||||||
|
db_create_tables()
|
||||||
|
|
||||||
logging.config.dictConfig(config['logging'])
|
logging.config.dictConfig(config['logging'])
|
||||||
redact_filter = MLogFilter()
|
redact_filter = MLogFilter()
|
||||||
logging.getLogger("werkzeug").addFilter(redact_filter)
|
logging.getLogger("werkzeug").addFilter(redact_filter)
|
||||||
|
@ -511,9 +481,6 @@ def main():
|
||||||
|
|
||||||
matrix_url = config['MATRIX_HOST'] + '/_matrix/client/v3'
|
matrix_url = config['MATRIX_HOST'] + '/_matrix/client/v3'
|
||||||
|
|
||||||
# setup the database connection
|
|
||||||
init_db()
|
|
||||||
|
|
||||||
asyncio.run(asmain())
|
asyncio.run(asmain())
|
||||||
|
|
||||||
logger.info('!! shutdown initiated !!')
|
logger.info('!! shutdown initiated !!')
|
||||||
|
|
Loading…
Reference in a new issue