1919from enum import Enum
2020from typing import Any , Dict , List , Optional , Tuple
2121
22- from synapse .api .constants import EventTypes , JoinRules
22+ from synapse .api .constants import EventContentFields , EventTypes , JoinRules
2323from synapse .api .errors import StoreError
2424from synapse .api .room_versions import RoomVersion , RoomVersions
25+ from synapse .events import EventBase
2526from synapse .storage ._base import SQLBaseStore , db_to_json
2627from synapse .storage .database import DatabasePool , LoggingTransaction
2728from synapse .storage .databases .main .search import SearchStore
@@ -1013,6 +1014,7 @@ class _BackgroundUpdates:
10131014 ADD_ROOMS_ROOM_VERSION_COLUMN = "add_rooms_room_version_column"
10141015 POPULATE_ROOM_DEPTH_MIN_DEPTH2 = "populate_room_depth_min_depth2"
10151016 REPLACE_ROOM_DEPTH_MIN_DEPTH = "replace_room_depth_min_depth"
1017+ POPULATE_ROOMS_CREATOR_COLUMN = "populate_rooms_creator_column"
10161018
10171019
10181020_REPLACE_ROOM_DEPTH_SQL_COMMANDS = (
@@ -1054,6 +1056,11 @@ def __init__(self, database: DatabasePool, db_conn, hs):
10541056 self ._background_replace_room_depth_min_depth ,
10551057 )
10561058
1059+ self .db_pool .updates .register_background_update_handler (
1060+ _BackgroundUpdates .POPULATE_ROOMS_CREATOR_COLUMN ,
1061+ self ._background_populate_rooms_creator_column ,
1062+ )
1063+
10571064 async def _background_insert_retention (self , progress , batch_size ):
10581065 """Retrieves a list of all rooms within a range and inserts an entry for each of
10591066 them into the room_retention table.
@@ -1273,7 +1280,7 @@ async def has_auth_chain_index(self, room_id: str) -> bool:
12731280 keyvalues = {"room_id" : room_id },
12741281 retcol = "MAX(stream_ordering)" ,
12751282 allow_none = True ,
1276- desc = "upsert_room_on_join " ,
1283+ desc = "has_auth_chain_index_fallback " ,
12771284 )
12781285
12791286 return max_ordering is None
@@ -1343,14 +1350,75 @@ def process(txn: Cursor) -> None:
13431350
13441351 return 0
13451352
1353+ async def _background_populate_rooms_creator_column (
1354+ self , progress : dict , batch_size : int
1355+ ):
1356+ """Background update to go and add creator information to `rooms`
1357+ table from `current_state_events` table.
1358+ """
1359+
1360+ last_room_id = progress .get ("room_id" , "" )
1361+
1362+ def _background_populate_rooms_creator_column_txn (txn : LoggingTransaction ):
1363+ sql = """
1364+ SELECT room_id, json FROM event_json
1365+ INNER JOIN rooms AS room USING (room_id)
1366+ INNER JOIN current_state_events AS state_event USING (room_id, event_id)
1367+ WHERE room_id > ? AND (room.creator IS NULL OR room.creator = '') AND state_event.type = 'm.room.create' AND state_event.state_key = ''
1368+ ORDER BY room_id
1369+ LIMIT ?
1370+ """
1371+
1372+ txn .execute (sql , (last_room_id , batch_size ))
1373+ room_id_to_create_event_results = txn .fetchall ()
1374+
1375+ new_last_room_id = ""
1376+ for room_id , event_json in room_id_to_create_event_results :
1377+ event_dict = db_to_json (event_json )
1378+
1379+ creator = event_dict .get ("content" ).get (EventContentFields .ROOM_CREATOR )
1380+
1381+ self .db_pool .simple_update_txn (
1382+ txn ,
1383+ table = "rooms" ,
1384+ keyvalues = {"room_id" : room_id },
1385+ updatevalues = {"creator" : creator },
1386+ )
1387+ new_last_room_id = room_id
1388+
1389+ if new_last_room_id == "" :
1390+ return True
1391+
1392+ self .db_pool .updates ._background_update_progress_txn (
1393+ txn ,
1394+ _BackgroundUpdates .POPULATE_ROOMS_CREATOR_COLUMN ,
1395+ {"room_id" : new_last_room_id },
1396+ )
1397+
1398+ return False
1399+
1400+ end = await self .db_pool .runInteraction (
1401+ "_background_populate_rooms_creator_column" ,
1402+ _background_populate_rooms_creator_column_txn ,
1403+ )
1404+
1405+ if end :
1406+ await self .db_pool .updates ._end_background_update (
1407+ _BackgroundUpdates .POPULATE_ROOMS_CREATOR_COLUMN
1408+ )
1409+
1410+ return batch_size
1411+
13461412
13471413class RoomStore (RoomBackgroundUpdateStore , RoomWorkerStore , SearchStore ):
13481414 def __init__ (self , database : DatabasePool , db_conn , hs ):
13491415 super ().__init__ (database , db_conn , hs )
13501416
13511417 self .config = hs .config
13521418
1353- async def upsert_room_on_join (self , room_id : str , room_version : RoomVersion ):
1419+ async def upsert_room_on_join (
1420+ self , room_id : str , room_version : RoomVersion , auth_events : List [EventBase ]
1421+ ):
13541422 """Ensure that the room is stored in the table
13551423
13561424 Called when we join a room over federation, and overwrites any room version
@@ -1361,14 +1429,32 @@ async def upsert_room_on_join(self, room_id: str, room_version: RoomVersion):
13611429 # mark the room as having an auth chain cover index.
13621430 has_auth_chain_index = await self .has_auth_chain_index (room_id )
13631431
1432+ create_event = None
1433+ for e in auth_events :
1434+ if (e .type , e .state_key ) == (EventTypes .Create , "" ):
1435+ create_event = e
1436+ break
1437+
1438+ if create_event is None :
1439+ # If the state doesn't have a create event then the room is
1440+ # invalid, and it would fail auth checks anyway.
1441+ raise StoreError (400 , "No create event in state" )
1442+
1443+ room_creator = create_event .content .get (EventContentFields .ROOM_CREATOR )
1444+
1445+ if not isinstance (room_creator , str ):
1446+ # If the create event does not have a creator then the room is
1447+ # invalid, and it would fail auth checks anyway.
1448+ raise StoreError (400 , "No creator defined on the create event" )
1449+
13641450 await self .db_pool .simple_upsert (
13651451 desc = "upsert_room_on_join" ,
13661452 table = "rooms" ,
13671453 keyvalues = {"room_id" : room_id },
13681454 values = {"room_version" : room_version .identifier },
13691455 insertion_values = {
13701456 "is_public" : False ,
1371- "creator" : "" ,
1457+ "creator" : room_creator ,
13721458 "has_auth_chain_index" : has_auth_chain_index ,
13731459 },
13741460 # rooms has a unique constraint on room_id, so no need to lock when doing an
@@ -1396,6 +1482,9 @@ async def maybe_store_room_on_outlier_membership(
13961482 insertion_values = {
13971483 "room_version" : room_version .identifier ,
13981484 "is_public" : False ,
1485+ # We don't worry about setting the `creator` here because
1486+ # we don't process any messages in a room while a user is
1487+ # invited (only after the join).
13991488 "creator" : "" ,
14001489 "has_auth_chain_index" : has_auth_chain_index ,
14011490 },
0 commit comments