Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 301b415

Browse files
authored
Add column full_user_id to tables profiles and user_filters. (#15458)
1 parent 247e6a8 commit 301b415

17 files changed

Lines changed: 186 additions & 74 deletions

File tree

changelog.d/15458.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add column `full_user_id` to tables `profiles` and `user_filters`.

synapse/_scripts/synapse_port_db.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
)
5555
from synapse.notifier import ReplicationNotifier
5656
from synapse.storage.database import DatabasePool, LoggingTransaction, make_conn
57-
from synapse.storage.databases.main import PushRuleStore
57+
from synapse.storage.databases.main import FilteringWorkerStore, PushRuleStore
5858
from synapse.storage.databases.main.account_data import AccountDataWorkerStore
5959
from synapse.storage.databases.main.client_ips import ClientIpBackgroundUpdateStore
6060
from synapse.storage.databases.main.deviceinbox import DeviceInboxBackgroundUpdateStore
@@ -69,6 +69,7 @@
6969
MediaRepositoryBackgroundUpdateStore,
7070
)
7171
from synapse.storage.databases.main.presence import PresenceBackgroundUpdateStore
72+
from synapse.storage.databases.main.profile import ProfileWorkerStore
7273
from synapse.storage.databases.main.pusher import (
7374
PusherBackgroundUpdatesStore,
7475
PusherWorkerStore,
@@ -229,6 +230,8 @@ class Store(
229230
EndToEndRoomKeyBackgroundStore,
230231
StatsStore,
231232
AccountDataWorkerStore,
233+
FilteringWorkerStore,
234+
ProfileWorkerStore,
232235
PushRuleStore,
233236
PusherWorkerStore,
234237
PusherBackgroundUpdatesStore,

synapse/api/filtering.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,9 @@ async def get_user_filter(
170170
result = await self.store.get_user_filter(user_localpart, filter_id)
171171
return FilterCollection(self._hs, result)
172172

173-
def add_user_filter(
174-
self, user_localpart: str, user_filter: JsonDict
175-
) -> Awaitable[int]:
173+
def add_user_filter(self, user_id: UserID, user_filter: JsonDict) -> Awaitable[int]:
176174
self.check_valid_filter(user_filter)
177-
return self.store.add_user_filter(user_localpart, user_filter)
175+
return self.store.add_user_filter(user_id, user_filter)
178176

179177
# TODO(paul): surely we should probably add a delete_user_filter or
180178
# replace_user_filter at some point? There's no REST API specified for

synapse/handlers/profile.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,7 @@ async def set_displayname(
178178
authenticated_entity=requester.authenticated_entity,
179179
)
180180

181-
await self.store.set_profile_displayname(
182-
target_user.localpart, displayname_to_set
183-
)
181+
await self.store.set_profile_displayname(target_user, displayname_to_set)
184182

185183
profile = await self.store.get_profileinfo(target_user.localpart)
186184
await self.user_directory_handler.handle_local_profile_change(
@@ -272,9 +270,7 @@ async def set_avatar_url(
272270
target_user, authenticated_entity=requester.authenticated_entity
273271
)
274272

275-
await self.store.set_profile_avatar_url(
276-
target_user.localpart, avatar_url_to_set
277-
)
273+
await self.store.set_profile_avatar_url(target_user, avatar_url_to_set)
278274

279275
profile = await self.store.get_profileinfo(target_user.localpart)
280276
await self.user_directory_handler.handle_local_profile_change(

synapse/rest/client/filter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ async def on_POST(
9494
set_timeline_upper_limit(content, self.hs.config.server.filter_timeline_limit)
9595

9696
filter_id = await self.filtering.add_user_filter(
97-
user_localpart=target_user.localpart, user_filter=content
97+
user_id=target_user, user_filter=content
9898
)
9999

100100
return 200, {"filter_id": str(filter_id)}

synapse/storage/databases/main/filtering.py

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,38 @@
1616
from typing import Optional, Tuple, Union, cast
1717

1818
from canonicaljson import encode_canonical_json
19+
from typing_extensions import TYPE_CHECKING
1920

2021
from synapse.api.errors import Codes, StoreError, SynapseError
2122
from synapse.storage._base import SQLBaseStore, db_to_json
22-
from synapse.storage.database import LoggingTransaction
23-
from synapse.types import JsonDict
23+
from synapse.storage.database import (
24+
DatabasePool,
25+
LoggingDatabaseConnection,
26+
LoggingTransaction,
27+
)
28+
from synapse.types import JsonDict, UserID
2429
from synapse.util.caches.descriptors import cached
2530

31+
if TYPE_CHECKING:
32+
from synapse.server import HomeServer
33+
2634

2735
class FilteringWorkerStore(SQLBaseStore):
36+
def __init__(
37+
self,
38+
database: DatabasePool,
39+
db_conn: LoggingDatabaseConnection,
40+
hs: "HomeServer",
41+
):
42+
super().__init__(database, db_conn, hs)
43+
self.db_pool.updates.register_background_index_update(
44+
"full_users_filters_unique_idx",
45+
index_name="full_users_unique_idx",
46+
table="user_filters",
47+
columns=["full_user_id, filter_id"],
48+
unique=True,
49+
)
50+
2851
@cached(num_args=2)
2952
async def get_user_filter(
3053
self, user_localpart: str, filter_id: Union[int, str]
@@ -46,7 +69,7 @@ async def get_user_filter(
4669

4770
return db_to_json(def_json)
4871

49-
async def add_user_filter(self, user_localpart: str, user_filter: JsonDict) -> int:
72+
async def add_user_filter(self, user_id: UserID, user_filter: JsonDict) -> int:
5073
def_json = encode_canonical_json(user_filter)
5174

5275
# Need an atomic transaction to SELECT the maximal ID so far then
@@ -56,24 +79,32 @@ def _do_txn(txn: LoggingTransaction) -> int:
5679
"SELECT filter_id FROM user_filters "
5780
"WHERE user_id = ? AND filter_json = ?"
5881
)
59-
txn.execute(sql, (user_localpart, bytearray(def_json)))
82+
txn.execute(sql, (user_id.localpart, bytearray(def_json)))
6083
filter_id_response = txn.fetchone()
6184
if filter_id_response is not None:
6285
return filter_id_response[0]
6386

6487
sql = "SELECT MAX(filter_id) FROM user_filters WHERE user_id = ?"
65-
txn.execute(sql, (user_localpart,))
88+
txn.execute(sql, (user_id.localpart,))
6689
max_id = cast(Tuple[Optional[int]], txn.fetchone())[0]
6790
if max_id is None:
6891
filter_id = 0
6992
else:
7093
filter_id = max_id + 1
7194

7295
sql = (
73-
"INSERT INTO user_filters (user_id, filter_id, filter_json)"
74-
"VALUES(?, ?, ?)"
96+
"INSERT INTO user_filters (full_user_id, user_id, filter_id, filter_json)"
97+
"VALUES(?, ?, ?, ?)"
98+
)
99+
txn.execute(
100+
sql,
101+
(
102+
user_id.to_string(),
103+
user_id.localpart,
104+
filter_id,
105+
bytearray(def_json),
106+
),
75107
)
76-
txn.execute(sql, (user_localpart, filter_id, bytearray(def_json)))
77108

78109
return filter_id
79110

synapse/storage/databases/main/profile.py

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,34 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14-
from typing import Optional
14+
from typing import TYPE_CHECKING, Optional
1515

1616
from synapse.api.errors import StoreError
1717
from synapse.storage._base import SQLBaseStore
18+
from synapse.storage.database import DatabasePool, LoggingDatabaseConnection
1819
from synapse.storage.databases.main.roommember import ProfileInfo
20+
from synapse.types import UserID
21+
22+
if TYPE_CHECKING:
23+
from synapse.server import HomeServer
1924

2025

2126
class ProfileWorkerStore(SQLBaseStore):
27+
def __init__(
28+
self,
29+
database: DatabasePool,
30+
db_conn: LoggingDatabaseConnection,
31+
hs: "HomeServer",
32+
):
33+
super().__init__(database, db_conn, hs)
34+
self.db_pool.updates.register_background_index_update(
35+
"profiles_full_user_id_key_idx",
36+
index_name="profiles_full_user_id_key",
37+
table="profiles",
38+
columns=["full_user_id"],
39+
unique=True,
40+
)
41+
2242
async def get_profileinfo(self, user_localpart: str) -> ProfileInfo:
2343
try:
2444
profile = await self.db_pool.simple_select_one(
@@ -54,28 +74,36 @@ async def get_profile_avatar_url(self, user_localpart: str) -> Optional[str]:
5474
desc="get_profile_avatar_url",
5575
)
5676

57-
async def create_profile(self, user_localpart: str) -> None:
77+
async def create_profile(self, user_id: UserID) -> None:
78+
user_localpart = user_id.localpart
5879
await self.db_pool.simple_insert(
59-
table="profiles", values={"user_id": user_localpart}, desc="create_profile"
80+
table="profiles",
81+
values={"user_id": user_localpart, "full_user_id": user_id.to_string()},
82+
desc="create_profile",
6083
)
6184

6285
async def set_profile_displayname(
63-
self, user_localpart: str, new_displayname: Optional[str]
86+
self, user_id: UserID, new_displayname: Optional[str]
6487
) -> None:
88+
user_localpart = user_id.localpart
6589
await self.db_pool.simple_upsert(
6690
table="profiles",
6791
keyvalues={"user_id": user_localpart},
68-
values={"displayname": new_displayname},
92+
values={
93+
"displayname": new_displayname,
94+
"full_user_id": user_id.to_string(),
95+
},
6996
desc="set_profile_displayname",
7097
)
7198

7299
async def set_profile_avatar_url(
73-
self, user_localpart: str, new_avatar_url: Optional[str]
100+
self, user_id: UserID, new_avatar_url: Optional[str]
74101
) -> None:
102+
user_localpart = user_id.localpart
75103
await self.db_pool.simple_upsert(
76104
table="profiles",
77105
keyvalues={"user_id": user_localpart},
78-
values={"avatar_url": new_avatar_url},
106+
values={"avatar_url": new_avatar_url, "full_user_id": user_id.to_string()},
79107
desc="set_profile_avatar_url",
80108
)
81109

synapse/storage/databases/main/registration.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2414,8 +2414,8 @@ def _register_user(
24142414
# *obviously* the 'profiles' table uses localpart for user_id
24152415
# while everything else uses the full mxid.
24162416
txn.execute(
2417-
"INSERT INTO profiles(user_id, displayname) VALUES (?,?)",
2418-
(user_id_obj.localpart, create_profile_with_displayname),
2417+
"INSERT INTO profiles(full_user_id, user_id, displayname) VALUES (?,?,?)",
2418+
(user_id, user_id_obj.localpart, create_profile_with_displayname),
24192419
)
24202420

24212421
if self.hs.config.stats.stats_enabled:

synapse/storage/schema/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
SCHEMA_VERSION = 75 # remember to update the list below when updating
15+
SCHEMA_VERSION = 76 # remember to update the list below when updating
1616
"""Represents the expectations made by the codebase about the database schema
1717
1818
This should be incremented whenever the codebase changes its requirements on the
@@ -97,6 +97,9 @@
9797
`local_current_membership` & `room_memberships`) is now being populated for new
9898
rows. When the background job to populate historical rows lands this will
9999
become the compat schema version.
100+
101+
Changes in SCHEMA_VERSION = 76:
102+
- Adds a full_user_id column to tables profiles and user_filters.
100103
"""
101104

102105

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/* Copyright 2023 The Matrix.org Foundation C.I.C
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
ALTER TABLE profiles ADD COLUMN full_user_id TEXT;
17+
18+
-- Make sure the column has a unique constraint, mirroring the `profiles_user_id_key`
19+
-- constraint.
20+
INSERT INTO background_updates (ordering, update_name, progress_json) VALUES (7501, 'profiles_full_user_id_key_idx', '{}');

0 commit comments

Comments
 (0)