From abfefab545f9b74a3e5d383fe8aa673ed21a6567 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 23 Mar 2021 20:13:06 +0200 Subject: [PATCH] Store puppet displayname quality and don't allow it to decrease --- ...02_store_displayname_quality_in_puppet_.py | 32 +++++++++++++++++++ mautrix_telegram/db/puppet.py | 3 +- mautrix_telegram/puppet.py | 31 +++++++++++------- 3 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 alembic/versions/bfc0a39bfe02_store_displayname_quality_in_puppet_.py diff --git a/alembic/versions/bfc0a39bfe02_store_displayname_quality_in_puppet_.py b/alembic/versions/bfc0a39bfe02_store_displayname_quality_in_puppet_.py new file mode 100644 index 00000000..df30f3d7 --- /dev/null +++ b/alembic/versions/bfc0a39bfe02_store_displayname_quality_in_puppet_.py @@ -0,0 +1,32 @@ +"""Store displayname quality in puppet table + +Revision ID: bfc0a39bfe02 +Revises: ec1d3dcc77e9 +Create Date: 2021-03-23 20:03:08.825333 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = 'bfc0a39bfe02' +down_revision = 'ec1d3dcc77e9' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('puppet', schema=None) as batch_op: + batch_op.add_column(sa.Column('displayname_quality', sa.Integer(), server_default='0', nullable=False)) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('puppet', schema=None) as batch_op: + batch_op.drop_column('displayname_quality') + + # ### end Alembic commands ### diff --git a/mautrix_telegram/db/puppet.py b/mautrix_telegram/db/puppet.py index 14ab6d3f..f842a14e 100644 --- a/mautrix_telegram/db/puppet.py +++ b/mautrix_telegram/db/puppet.py @@ -15,7 +15,7 @@ # along with this program. If not, see . from typing import Optional, Iterable -from sqlalchemy import Column, BigInteger, String, Text, Boolean +from sqlalchemy import Column, Integer, BigInteger, String, Text, Boolean from sqlalchemy.sql import expression, func from mautrix.types import UserID, SyncToken @@ -35,6 +35,7 @@ class Puppet(Base): displayname: str = Column(String, nullable=True) displayname_source: TelegramID = Column(BigInteger, nullable=True) displayname_contact: bool = Column(Boolean, nullable=False, server_default=expression.true()) + displayname_quality: int = Column(Integer, nullable=False, server_default="0") username: str = Column(String, nullable=True) photo_id: str = Column(String, nullable=True) is_bot: bool = Column(Boolean, nullable=True) diff --git a/mautrix_telegram/puppet.py b/mautrix_telegram/puppet.py index 7048ac3b..01cbb781 100644 --- a/mautrix_telegram/puppet.py +++ b/mautrix_telegram/puppet.py @@ -13,7 +13,7 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from typing import Awaitable, Any, Dict, Iterable, Optional, Union, TYPE_CHECKING +from typing import Awaitable, Any, Dict, Iterable, Optional, Union, Tuple, TYPE_CHECKING from difflib import SequenceMatcher import unicodedata import asyncio @@ -66,6 +66,7 @@ class Puppet(BasePuppet): displayname: Optional[str] displayname_source: Optional[TelegramID] displayname_contact: bool + displayname_quality: int photo_id: Optional[str] is_bot: bool is_registered: bool @@ -88,6 +89,7 @@ class Puppet(BasePuppet): displayname: Optional[str] = None, displayname_source: Optional[TelegramID] = None, displayname_contact: bool = True, + displayname_quality: int = 0, photo_id: Optional[str] = None, is_bot: bool = False, is_registered: bool = False, @@ -104,6 +106,7 @@ class Puppet(BasePuppet): self.displayname = displayname self.displayname_source = displayname_source self.displayname_contact = displayname_contact + self.displayname_quality = displayname_quality self.photo_id = photo_id self.is_bot = is_bot self.is_registered = is_registered @@ -168,7 +171,8 @@ class Puppet(BasePuppet): return dict(access_token=self.access_token, next_batch=self._next_batch, custom_mxid=self.custom_mxid, username=self.username, is_bot=self.is_bot, displayname=self.displayname, displayname_source=self.displayname_source, - displayname_contact=self.displayname_contact, photo_id=self.photo_id, + displayname_contact=self.displayname_contact, + displayname_quality=self.displayname_quality, photo_id=self.photo_id, matrix_registered=self.is_registered, disable_updates=self.disable_updates, base_url=str(self.base_url) if self.base_url else None) @@ -183,9 +187,9 @@ class Puppet(BasePuppet): return Puppet(db_puppet.id, db_puppet.access_token, db_puppet.custom_mxid, db_puppet.next_batch, db_puppet.base_url, db_puppet.username, db_puppet.displayname, db_puppet.displayname_source, - db_puppet.displayname_contact, db_puppet.photo_id, db_puppet.is_bot, - db_puppet.matrix_registered, db_puppet.disable_updates, - db_instance=db_puppet) + db_puppet.displayname_contact, db_puppet.displayname_quality, + db_puppet.photo_id, db_puppet.is_bot, db_puppet.matrix_registered, + db_puppet.disable_updates, db_instance=db_puppet) # endregion # region Info updating @@ -209,7 +213,7 @@ class Puppet(BasePuppet): return name @classmethod - def get_displayname(cls, info: User, enable_format: bool = True) -> str: + def get_displayname(cls, info: User, enable_format: bool = True) -> Tuple[str, int]: fn = cls._filter_name(info.first_name) ln = cls._filter_name(info.last_name) data = { @@ -222,19 +226,21 @@ class Puppet(BasePuppet): } preferences = config["bridge.displayname_preference"] name = None + quality = 99 for preference in preferences: name = data[preference] if name: break + quality -= 1 if isinstance(info, User) and info.deleted: name = f"Deleted account {info.id}" + quality = 99 elif not name: name = str(info.id) + quality = 0 - if not enable_format: - return name - return cls.displayname_template.format_full(name) + return cls.displayname_template.format_full(name) if enable_format else name, quality async def try_update_info(self, source: 'AbstractUser', info: User) -> None: try: @@ -287,13 +293,15 @@ class Puppet(BasePuppet): else: return False - displayname = self.get_displayname(info) - if displayname != self.displayname: + displayname, quality = self.get_displayname(info) + if displayname != self.displayname and quality >= self.displayname_quality: + allow_because = f"{allow_because} and quality {quality} >= {self.displayname_quality}" self.log.debug(f"Updating displayname of {self.id} (src: {source.tgid}, allowed " f"because {allow_because}) from {self.displayname} to {displayname}") self.log.trace("Displayname source data: %s", info) self.displayname = displayname self.displayname_source = source.tgid + self.displayname_quality = quality try: await self.default_mxid_intent.set_displayname( displayname[:config["bridge.displayname_max_length"]]) @@ -301,6 +309,7 @@ class Puppet(BasePuppet): self.log.exception("Failed to set displayname") self.displayname = "" self.displayname_source = None + self.displayname_quality = 0 return True elif source.is_relaybot or self.displayname_source is None: self.displayname_source = source.tgid