From 9dc5e3eda9bf01f3af12ad9581f3236772b298b9 Mon Sep 17 00:00:00 2001 From: Morgan McMillian Date: Tue, 24 Mar 2020 22:39:09 -0700 Subject: [PATCH] added direct chat support with bridge removing the need for seperate bot, issue #35 --- appservice.py | 159 +++++++++++++++++++++++++++++++++++++++++++++++++- models.py | 5 ++ 2 files changed, 162 insertions(+), 2 deletions(-) diff --git a/appservice.py b/appservice.py index fc4e4a1..f4e6b2c 100644 --- a/appservice.py +++ b/appservice.py @@ -6,7 +6,7 @@ import pnutpy from matrix_client.api import MatrixHttpApi from matrix_client.api import MatrixError, MatrixRequestError -from models import Avatars, Rooms, Events, Users +from models import Avatars, Rooms, Events, Users, DirectRooms from database import db_session from sqlalchemy import and_ from flask import Flask, jsonify, request, abort @@ -105,7 +105,17 @@ def on_receive_events(transaction): delete_message(event, user) elif event['type'] == 'm.room.member': - logger.debug("-room member event") + if 'is_direct' in event['content'] and 'membership' in event['content']: + if event['content']['membership'] == "invite" and event['content']['is_direct']: + return on_admin_invite(event) + + if 'membership' in event['content']: + if event['content']['membership'] == "leave": + return on_leave_event(event) + + logger.debug("----room member event----") + logger.debug(user) + logger.debug(event) return jsonify({}) @@ -115,6 +125,10 @@ def new_message(event, user): logger.debug('-skipping dup event-') return + direct = DirectRooms.query.filter(DirectRooms.room_id == event['room_id']).one_or_none() + if direct is not None: + return on_direct_message(event) + room = Rooms.query.filter(Rooms.room_id == event['room_id']).one_or_none() if room is None: logger.debug('-room not mapped-') @@ -448,3 +462,144 @@ def cmd_admin_unlink(id): errmsg = "- error while unlinking room -" logger.exception(errmsg) return errmsg + +def on_admin_invite(event): + matrix_api = MatrixHttpApi(app.config['MATRIX_HOST'], + token=app.config['MATRIX_AS_TOKEN']) + + matrix_api.join_room(event['room_id']) + + direct = DirectRooms(room_id=event['room_id']) + db_session.add(direct) + db_session.commit() + + return jsonify({}) + +def on_leave_event(event): + matrix_api = MatrixHttpApi(app.config['MATRIX_HOST'], + token=app.config['MATRIX_AS_TOKEN']) + + direct = DirectRooms.query.filter(DirectRooms.room_id == event['room_id']).one_or_none() + if direct is not None: + db_session.delete(direct) + db_session.commit() + matrix_api.leave_room(event['room_id']) + + return jsonify({}) + +def on_direct_message(event): + matrix_api = MatrixHttpApi(app.config['MATRIX_HOST'], + token=app.config['MATRIX_AS_TOKEN']) + logger.debug("- direct room event received -") + + if event['type'] != 'm.room.message': + return jsonify({}) + + msg = event['content']['body'].split(' ') + + if msg[0] == '!help' or msg[0] == 'help': + if len(msg) > 1: + matrix_api.send_message(event['room_id'], cmd_user_help(msg[1])) + else: + matrix_api.send_message(event['room_id'], cmd_user_help()) + + elif msg[0] == '!auth': + matrix_api.send_message(event['room_id'], cmd_user_auth()) + + elif msg[0] == '!save': + if len(msg) > 1: + matrix_api.send_message(event['room_id'], cmd_user_save(event['sender'], msg[1])) + else: + matrix_api.send_message(event['room_id'], cmd_user_save()) + + elif msg[0] == '!drop': + matrix_api.send_message(event['room_id'], cmd_user_drop(event['sender'])) + + elif msg[0] == '!status': + matrix_api.send_message(event['room_id'], cmd_user_status(event['sender'])) + + return jsonify({}) + +def cmd_user_help(cmd=None): + reply = "This is an admin room for controlling your connection to pnut.io\n" + reply += "The following commands are available.\n\n" + reply += "!auth\t\t\t- Authorize your account on pnut.io\n" + reply += "!save \t- Save your pnut.io auth token\n" + reply += "!drop\t\t\t- Drop your pnut.io auth token\n" + reply += "!status\t\t\t- Status of your pnut.io auth token\n" + + return reply + +def cmd_user_auth(): + reply = "Visit the following URL to authorize your account on pnut.io.\n\n" + reply += "https://pnut.io/oauth/authenticate" + reply += "?client_id=6SeCRCpCZkmZOKFLFGWbcdAeq2fX1M5t" + reply += "&redirect_uri=urn:ietf:wg:oauth:2.0:oob" + reply += "&scope=write_post,presence,messages&response_type=token\n\n" + reply += "You will be provided with a token that you store with the !save command.\n" + + return reply + +def cmd_user_save(sender=None, token=None): + if token is None: + reply = "You must provide a token with this command.\n" + reply += "!save " + return reply + + pnutpy.api.add_authorization_token(token) + try: + response, meta = pnutpy.api.get_user('me') + + user = Users( + matrix_id=sender, + pnut_user_id=response.id, + pnut_user_token=token + ) + db_session.add(user) + db_session.commit() + + reply = "Success! You are now authorized as " + response['username'] + + except pnutpy.errors.PnutAuthAPIException as e: + reply = "Error! Unable to authorize your account." + + except Exception as e: + logging.exception('!save') + reply = "Error! Problem saving your token." + + return reply + +def cmd_user_drop(sender=None): + 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: + logging.exception('!drop') + reply = "Error! Problem removing your token." + + return reply + +def cmd_user_status(sender=None): + try: + user = Users.query.filter(Users.matrix_id == sender).one_or_none() + if user is None: + reply = "You are currently not authorized on pnut.io" + else: + pnutpy.api.add_authorization_token(user.pnut_user_token) + response, meta = pnutpy.api.get_user('me') + reply = "You are currently authorized as " + response.username + + except pnutpy.errors.PnutAuthAPIException as e: + reply = "You are currently not authorized on pnut.io" + + except Exception as e: + logging.exception('!status') + reply = "Error! There was a problem checking your account." + + return reply diff --git a/models.py b/models.py index ecd6fb1..a201b60 100644 --- a/models.py +++ b/models.py @@ -14,6 +14,11 @@ class Rooms(Base): pnut_chan = Column(Integer, unique=True) portal = Column(Boolean) +class DirectRooms(Base): + __tablename__ = 'direct' + id = Column(Integer, primary_key=True) + room_id = Column(String(250), unique=True) + class Events(Base): __tablename__ = 'events' id = Column(Integer, primary_key=True)