diff --git a/linkedin.db b/linkedin.db new file mode 100644 index 0000000..63b4cd6 Binary files /dev/null and b/linkedin.db differ diff --git a/linkedin_matrix/commands/__init__.py b/linkedin_matrix/commands/__init__.py index be5366e..e9790b5 100644 --- a/linkedin_matrix/commands/__init__.py +++ b/linkedin_matrix/commands/__init__.py @@ -1,3 +1,4 @@ from .auth import SECTION_AUTH, login +from .spaces import SECTION_SPACES -__all__ = ("SECTION_AUTH", "login") +__all__ = ("SECTION_AUTH", "SECTION_SPACES", "login") diff --git a/linkedin_matrix/commands/spaces.py b/linkedin_matrix/commands/spaces.py new file mode 100644 index 0000000..cc322df --- /dev/null +++ b/linkedin_matrix/commands/spaces.py @@ -0,0 +1,63 @@ +import logging + +from mautrix.bridge.commands import HelpSection, command_handler +from mautrix.types import EventType + +from ..portal import Portal +from ..puppet import Puppet +from .typehint import CommandEvent + +SECTION_SPACES = HelpSection("Miscellaneous", 30, "") + + +@command_handler( + needs_auth=True, + management_only=False, + help_section=SECTION_SPACES, + help_text="Synchronize your personal filtering space", +) +async def sync_space(evt: CommandEvent): + if not evt.bridge.config["bridge.space_support.enable"]: + await evt.reply("Spaces are not enabled on this instance of the bridge") + return + + await evt.sender.create_or_update_space() + + if not evt.sender.space_mxid: + await evt.reply("Failed to create or update space") + return + + async for portal in Portal.all(): + if not portal.mxid: + logging.debug(f"Portal {portal} has no mxid") + continue + if portal.li_receiver_urn != evt.sender.li_member_urn: + logging.debug(f"Portal {portal} does not belong to {evt.sender}") + continue + + logging.debug(f"Adding chat {portal.mxid} to user's space ({evt.sender.space_mxid})") + try: + await evt.bridge.az.intent.send_state_event( + evt.sender.space_mxid, + EventType.SPACE_CHILD, + {"via": [evt.bridge.config["homeserver.domain"]], "suggested": True}, + state_key=str(portal.mxid), + ) + except Exception: + logging.warning( + f"Failed to add chat {portal.mxid} to user's space ({evt.sender.space_mxid})" + ) + + if not portal.li_is_group_chat: + logging.debug(f"Adding puppet {portal.li_other_user_urn} to user's space") + puppet = await Puppet.get_by_li_member_urn(portal.li_other_user_urn, create=False) + if not puppet: + continue + try: + await puppet.intent.ensure_joined(evt.sender.space_mxid) + except Exception as e: + logging.warning( + f"Failed to join {puppet.mxid} to user's space ({evt.sender.space_mxid}): {e}" + ) + + await evt.reply("Synced space") diff --git a/linkedin_matrix/db/puppet.py b/linkedin_matrix/db/puppet.py index 1afc2ae..435e907 100644 --- a/linkedin_matrix/db/puppet.py +++ b/linkedin_matrix/db/puppet.py @@ -58,6 +58,12 @@ def _from_row(cls, row: Record | None) -> Puppet | None: li_member_urn=URN(li_member_urn), ) + @classmethod + async def all(cls) -> list["Puppet"]: + query = Puppet.select_constructor() + rows = await cls.db.fetch(query) + return [cast(Puppet, cls._from_row(row)) for row in rows if row] + @classmethod async def get_by_li_member_urn(cls, li_member_urn: URN) -> Puppet | None: query = Puppet.select_constructor("li_member_urn=$1") diff --git a/linkedin_matrix/portal.py b/linkedin_matrix/portal.py index ff1d52c..061f709 100644 --- a/linkedin_matrix/portal.py +++ b/linkedin_matrix/portal.py @@ -631,7 +631,6 @@ async def _create_matrix_room( {"via": [self.config["homeserver.domain"]], "suggested": True}, state_key=str(self.mxid), ) - await self.az.intent.invite_user(source.space_mxid, source.mxid) except Exception: self.log.warning(f"Failed to add chat {self.mxid} to user's space") diff --git a/linkedin_matrix/user.py b/linkedin_matrix/user.py index ab3f533..d6423df 100644 --- a/linkedin_matrix/user.py +++ b/linkedin_matrix/user.py @@ -289,7 +289,7 @@ async def post_login(self): self.user_profile_cache = None self.log.exception("Failed to automatically enable custom puppet") - await self._create_or_update_space() + await self.create_or_update_space() await self.sync_threads() self.start_listen() @@ -326,7 +326,7 @@ async def logout(self): # Spaces support - async def _create_or_update_space(self): + async def create_or_update_space(self): if not self.config["bridge.space_support.enable"]: return @@ -365,6 +365,14 @@ async def _create_or_update_space(self): except Exception: self.log.warning(f"Failed to add bridge bot to new space {room}") + # Ensure that the user is invited and joined to the space. + try: + puppet = await pu.Puppet.get_by_custom_mxid(self.mxid) + if puppet and puppet.is_real_user: + await puppet.intent.ensure_joined(self.space_mxid) + except Exception: + self.log.warning(f"Failed to add user to the space {self.space_mxid}") + # endregion # region Thread Syncing