2022-09-29 18:19:35 +00:00
from asyncio import current_task , protocols
2022-09-28 18:04:21 +00:00
from dataclasses import dataclass , field
from typing import Dict , Any , Optional , Sequence
import logging
import nio
2022-09-29 18:19:35 +00:00
import synapse_admin
import asyncio
2022-09-28 18:04:21 +00:00
2022-09-29 18:19:35 +00:00
class MatrixAdminClient :
def __init__ ( self , server : str , access_token : str ) - > None :
protocol = server . split ( " :// " ) [ 0 ] + " :// "
server = server . split ( " :// " ) [ 1 ]
2022-09-28 18:04:21 +00:00
2022-09-29 18:19:35 +00:00
self . user = synapse_admin . User ( server , 443 , access_token , protocol )
self . room = synapse_admin . Room ( server , 443 , access_token , protocol )
self . media = synapse_admin . Media ( server , 443 , access_token , protocol )
self . management = synapse_admin . Management (
server , 443 , access_token , protocol )
2022-09-28 18:04:21 +00:00
class MatrixHelper :
2022-09-29 20:56:37 +00:00
ROOM_POWER_LEVEL_EVENTS = {
" m.room.encryption " : 200 ,
" m.room.avatar " : 50 ,
" m.room.name " : 50 ,
" m.room.canonical_alias " : 50 ,
" m.space.child " : 50 ,
" m.room.history_visibility " : 50 ,
" m.room.power_levels " : 50 ,
" m.room.topic " : 50 ,
" m.room.tombstone " : 50 ,
" m.room.server_acl " : 50 ,
" m.room.pinned_events " : 50 ,
" m.reaction " : 0 ,
" m.room.redaction " : 0 ,
" im.vector.modular.widgets " : 50 ,
" io.element.voice_broadcast_info " : 50
}
2022-09-29 18:19:35 +00:00
def __init__ ( self , server : str , username , space_id : str , matrix_username : str ) - > None :
2022-09-28 18:04:21 +00:00
self . _client = nio . AsyncClient ( server , username )
self . _loggedIn = False
self . _space_id = space_id
2022-09-29 18:19:35 +00:00
self . _server = server
self . _username = username
self . _matrix_username = matrix_username
def __del__ ( self ) :
asyncio . run ( self . logout ( ) )
2022-09-28 18:04:21 +00:00
async def login ( self , password ) :
try :
await self . _client . login ( password )
self . _loggedIn = True
logging . info ( f " Logged into Matrix as { await self . _client . get_displayname ( ) } " )
rooms = await self . _client . joined_rooms ( )
if self . _space_id not in rooms . rooms :
logging . error ( " The bot user is not in the space! " )
return False
2022-09-29 18:19:35 +00:00
# admin login
self . _admin_client = MatrixAdminClient (
self . _server , self . _client . access_token )
user = self . _admin_client . user . query ( self . _username )
logging . info ( f " Logged into Synapse-admin as { user [ ' name ' ] } " )
2022-09-28 18:04:21 +00:00
return True
except Exception as e :
2022-09-29 18:19:35 +00:00
print ( e )
2022-09-28 18:04:21 +00:00
logging . error ( f " Error while logging into matrix server! " )
return False
async def logout ( self ) :
await self . _client . close ( )
2022-09-29 20:13:09 +00:00
async def create_room ( self , name , alias , joinable_for_space_members = False , suggested = False ) :
2022-09-28 18:04:21 +00:00
# we not only need to create the room but also have to add it to the space
2022-09-29 20:13:09 +00:00
via_domain = self . _space_id . split ( " : " ) [ 1 ]
2022-09-28 18:04:21 +00:00
initial_state = [
{
" type " : " m.space.parent " ,
" state_key " : self . _space_id ,
" content " : {
" canonical " : True ,
2022-09-29 20:13:09 +00:00
" via " : [ via_domain ] ,
2022-09-28 18:04:21 +00:00
}
} ,
{
" type " : " m.room.history_visibility " ,
2022-09-29 18:19:35 +00:00
" content " : { " history_visibility " : " shared " }
} ,
{
" type " : " m.room.power_levels " ,
" content " : {
2022-09-29 20:56:37 +00:00
" events " : MatrixHelper . ROOM_POWER_LEVEL_EVENTS ,
" invite " : 50 ,
2022-09-29 18:19:35 +00:00
" users " : {
self . _matrix_username : 200 ,
}
}
2022-09-28 18:04:21 +00:00
}
]
2022-09-29 18:19:35 +00:00
if joinable_for_space_members :
2022-09-29 20:13:09 +00:00
initial_state . insert ( 0 , {
2022-09-29 18:19:35 +00:00
" type " : " m.room.guest_access " ,
" state_key " : " " ,
" content " : { " guest_access " : " can_join " }
} )
2022-09-29 20:13:09 +00:00
initial_state . insert ( 2 , {
" type " : " m.room.join_rules " ,
" content " : {
" join_rule " : " restricted " ,
" allow " : [
{
" type " : " m.room_membership " ,
" room_id " : self . _space_id
}
]
}
} )
2022-09-29 18:19:35 +00:00
2022-09-28 18:04:21 +00:00
room = await self . _client . room_create ( visibility = nio . RoomVisibility . private , name = name , alias = alias , federate = False , initial_state = initial_state )
2022-09-29 18:19:35 +00:00
assert room . room_id is not None
2022-09-29 20:13:09 +00:00
# add as child room
state_update = await self . _client . room_put_state ( self . _space_id , " m.space.child " , {
" suggested " : suggested ,
" via " : [ via_domain ] ,
} , state_key = room . room_id )
assert state_update . event_id is not None
2022-09-28 18:04:21 +00:00
return room
2022-09-29 18:19:35 +00:00
async def get_rooms ( self ) :
2023-02-11 09:38:19 +00:00
return self . _admin_client . room . lists ( limit = 200 , recent_first = False , orderby = " joined_local_members " )
2022-09-29 18:19:35 +00:00
async def get_users ( self ) :
return self . _admin_client . user . lists ( )
async def get_rooms_of_user ( self , username ) :
return self . _admin_client . user . joined_room ( username )
async def add_user_to_room ( self , user , room ) :
return self . _admin_client . user . join_room ( user , room )
async def remove_user_from_room ( self , user , room ) :
# TODO: Ban users?
return await self . _client . room_kick ( room , user , " You have been removed automatically since you are no longer a member of the group associated with this room. If you think, this is an error, please contact us. " )
async def get_room_power_levels ( self , room ) :
current_state = await self . _client . room_get_state_event ( room , " m.room.power_levels " )
return current_state . content [ ' users ' ]
async def set_user_power_level_in_room ( self , user , room , power_level ) :
if user == self . _matrix_username :
return False
if power_level != 100 and power_level != 50 and power_level != 0 :
return False
users = await self . get_room_power_levels ( room )
2022-10-04 08:24:46 +00:00
if not self . _matrix_username in users or users [ self . _matrix_username ] < 100 :
self . _admin_client . room . set_admin ( room , self . _matrix_username )
users = await self . get_room_power_levels ( room )
2022-09-29 18:19:35 +00:00
users [ user ] = power_level
2022-10-04 08:24:46 +00:00
room_power_level_events = MatrixHelper . ROOM_POWER_LEVEL_EVENTS
for key , value in room_power_level_events . items ( ) :
if value > users [ self . _matrix_username ] :
room_power_level_events [ key ] = users [ self . _matrix_username ]
2022-09-29 18:19:35 +00:00
2022-09-29 20:56:37 +00:00
result = await self . _client . room_put_state ( room , " m.room.power_levels " , {
2022-10-04 08:24:46 +00:00
" events " : room_power_level_events ,
2022-09-29 20:56:37 +00:00
" invite " : 50 ,
2022-09-29 18:19:35 +00:00
" users " : users
} )
2022-10-04 08:24:46 +00:00
if isinstance ( result , nio . ErrorResponse ) :
logging . error ( f " Error while setting power level of user { user } in room { room } to { power_level } " )
logging . error ( result )
logging . error ( f " Current power levels: { users } " )
return False
2022-09-29 20:56:37 +00:00
return True