diff --git a/README.md b/README.md
index 2cafa57..ca52744 100644
--- a/README.md
+++ b/README.md
@@ -176,6 +176,8 @@ Can search OpenStreetMaps for locations and send Matrix location events from the
Commands:
* !loc [location] - search for location
+* !loc enable - enable location to link translation in this room (must be done as room admin)
+* !loc disable - disable location to link translation in this room (must be done as room admin)
Example:
diff --git a/bot.py b/bot.py
index 21e22cb..cdff094 100755
--- a/bot.py
+++ b/bot.py
@@ -217,7 +217,7 @@ class Bot:
msg["org.vranki.hemppa.ignore"] = "true"
await self.client.room_send(room.room_id, 'm.room.message', msg)
- async def send_location(self, room, body, latitude, longitude, bot_ignore=False):
+ async def send_location(self, room, body, latitude, longitude, bot_ignore=False, asset='m.pin'):
"""
:param room: A MatrixRoom the html should be send to
@@ -226,12 +226,14 @@ class Bot:
:param latitude: Latitude in WGS84 coordinates (float)
:param longitude: Longitude in WGS84 coordinates (float)
:param bot_ignore: Flag to mark the message to be ignored by the bot
+ :param asset: Asset string as defined in MSC3488 (such as m.self or m.pin)
:return:
"""
locationmsg = {
"body": str(body),
"geo_uri": 'geo:' + str(latitude) + ',' + str(longitude),
"msgtype": "m.location",
+ "org.matrix.msc3488.asset": { "type": asset }
}
await self.client.room_send(room.room_id, 'm.room.message', locationmsg)
@@ -555,7 +557,6 @@ class Bot:
sys.exit(2)
def init(self):
-
self.matrix_user = os.getenv('MATRIX_USER')
matrix_server = os.getenv('MATRIX_SERVER')
bot_owners = os.getenv('BOT_OWNERS')
diff --git a/modules/loc.py b/modules/loc.py
index 04a8f4d..a17e976 100644
--- a/modules/loc.py
+++ b/modules/loc.py
@@ -5,7 +5,10 @@ from modules.common.module import BotModule
class MatrixModule(BotModule):
- bot = None
+ def __init__(self, name):
+ super().__init__(name)
+ self.bot = None
+ self.enabled_rooms = []
def matrix_start(self, bot):
super().matrix_start(bot)
@@ -16,30 +19,87 @@ class MatrixModule(BotModule):
super().matrix_stop(bot)
bot.remove_callback(self.unknown_cb)
+ '''
+ Location events are like: https://spec.matrix.org/v1.2/client-server-api/#mlocation
+ {
+ "content": {
+ "body": "geo:61.49342512194717,23.765914658307736",
+ "geo_uri": "geo:61.49342512194717,23.765914658307736",
+ "msgtype": "m.location",
+ "org.matrix.msc1767.text": "geo:61.49342512194717,23.765914658307736",
+ "org.matrix.msc3488.asset": {
+ "type": "m.pin"
+ },
+ "org.matrix.msc3488.location": {
+ "description": "geo:61.49342512194717,23.765914658307736",
+ "uri": "geo:61.49342512194717,23.765914658307736"
+ },
+ "org.matrix.msc3488.ts": 1653837929839
+ },
+ "room_id": "!xsBGdLYGrfYhGfLtHG:hacklab.fi",
+ "type": "m.room.message"
+ }
+
+ BUT sometimes there's ; separating altitude??
+ {
+ "content": {
+ "body": "geo:61.4704211,23.4864855;36.900001525878906",
+ "geo_uri": "geo:61.4704211,23.4864855;36.900001525878906",
+ "msgtype": "m.location",
+ "org.matrix.msc1767.text": "geo:61.4704211,23.4864855;36.900001525878906",
+ "org.matrix.msc3488.asset": {
+ "type": "m.self"
+ },
+ "org.matrix.msc3488.location": {
+ "description": "geo:61.4704211,23.4864855;36.900001525878906",
+ "uri": "geo:61.4704211,23.4864855;36.900001525878906"
+ },
+ "org.matrix.msc3488.ts": 1653931683087
+ },
+ "origin_server_ts": 1653931683998,
+ "sender": "@cos:hacklab.fi",
+ "type": "m.room.message",
+ "unsigned": {
+ "age": 70
+ },
+ "event_id": "$6xXutKF9EppPMMdc4aQLZjHyd8My0rIZuNZEcuSIPws",
+ "room_id": "!CLofqdurVWZCMpFnqM:hacklab.fi"
+}
+ '''
+
async def unknown_cb(self, room, event):
if event.msgtype != 'm.location':
return
+ if room.room_id not in self.enabled_rooms:
+ return
location_text = event.content['body']
# Fallback if body is empty
- if len(location_text) == 0:
+ if (len(location_text) == 0) or ('geo:' in location_text):
location_text = 'location'
sender_response = await self.bot.client.get_displayname(event.sender)
sender = sender_response.displayname
geo_uri = event.content['geo_uri']
- latlon = geo_uri.split(':')[1].split(',')
+ try:
+ geo_uri = geo_uri[4:] # Strip geo:
- # Sanity checks to avoid url manipulation
- float(latlon[0])
- float(latlon[1])
+ if ';' in geo_uri: # Strip altitude, if present
+ geo_uri = geo_uri.split(';')[0]
+ latlon = geo_uri.split(',')
- osm_link = 'https://www.openstreetmap.org/?mlat=' + \
- latlon[0] + "&mlon=" + latlon[1]
+ # Sanity checks to avoid url manipulation
+ float(latlon[0])
+ float(latlon[1])
+ except Exception:
+ self.bot.send_text(room, "Error: Invalid location " + geo_uri)
+ return
- plain = sender + ' 🚩 ' + osm_link
- html = f'{sender} 🚩 {location_text}'
+ osm_link = f"https://www.openstreetmap.org/?mlat={latlon[0]}&mlon={latlon[1]}"
+
+ plain = f'{sender} sent {location_text} {osm_link} 🚩'
+ html = f'{sender} sent {location_text} 🚩'
await self.bot.send_html(room, html, plain)
@@ -48,16 +108,41 @@ class MatrixModule(BotModule):
args.pop(0)
if len(args) == 0:
await bot.send_text(room, 'Usage: !loc ')
+ return
+ elif len(args) == 1:
+ if args[0] == 'enable':
+ bot.must_be_admin(room, event)
+ self.enabled_rooms.append(room.room_id)
+ self.enabled_rooms = list(dict.fromkeys(self.enabled_rooms)) # Deduplicate
+ await bot.send_text(room, "Ok, sending locations events here as text versions")
+ bot.save_settings()
+ return
+ if args[0] == 'disable':
+ bot.must_be_admin(room, event)
+ self.enabled_rooms.remove(room.room_id)
+ await bot.send_text(room, "Ok, disabled here")
+ bot.save_settings()
+ return
+
+ query = event.body[4:]
+ geolocator = Nominatim(user_agent=bot.appid)
+ self.logger.info('loc: looking up %s ..', query)
+ location = geolocator.geocode(query)
+ self.logger.info('loc rx %s', location)
+ if location:
+ await bot.send_location(room, location.address, location.latitude, location.longitude, "m.pin")
else:
- query = event.body[4:]
- geolocator = Nominatim(user_agent=bot.appid)
- self.logger.info('loc: looking up %s ..', query)
- location = geolocator.geocode(query)
- self.logger.info('loc rx %s', location)
- if location:
- await bot.send_location(room, location.address, location.latitude, location.longitude)
- else:
- await bot.send_text(room, "Can't find " + query + " on map!")
+ await bot.send_text(room, "Can't find " + query + " on map!")
def help(self):
return 'Search for locations and display Matrix location events as OSM links'
+
+ def get_settings(self):
+ data = super().get_settings()
+ data["enabled_rooms"] = self.enabled_rooms
+ return data
+
+ def set_settings(self, data):
+ super().set_settings(data)
+ if data.get("enabled_rooms"):
+ self.enabled_rooms = data["enabled_rooms"]