Skip to content
Snippets Groups Projects
Commit 1ce25b2b authored by Tulir Asokan's avatar Tulir Asokan :cat2:
Browse files

Add sync command and option to not sync avatars when syncing contacts

parent e29d68db
No related branches found
No related tags found
No related merge requests found
......@@ -85,6 +85,8 @@ bridge:
# Whether or not to bridge presence in both directions. Facebook allows users not to broadcast
# presence, but then it won't send other users' presence to the client.
presence: true
# Whether or not to update avatars when syncing all contacts at startup.
update_avatar_initial_sync: true
# Permissions for using the bridge.
# Permitted values:
......
......@@ -16,9 +16,10 @@
from typing import Iterable, List
import asyncio
from fbchat.models import User
from fbchat.models import User, ThreadLocation
from .. import puppet as pu, user as u
from .. import puppet as pu, portal as po, user as u
from ..db import UserPortal as DBUserPortal
from . import command_handler, CommandEvent, SECTION_MISC
......@@ -47,3 +48,33 @@ async def _handle_search_result(sender: 'u.User', res: Iterable[User]) -> str:
return f"Search results:\n\n{results}"
else:
return "No results :("
@command_handler(needs_auth=True, management_only=False, help_section=SECTION_MISC,
help_text="Synchronize portals", help_args="[_limit_] [--create] [--contacts]")
async def sync(evt: CommandEvent) -> None:
contacts = False
create_portals = False
limit = 0
for arg in evt.args:
arg = arg.lower()
if arg == "--contacts":
contacts = True
elif arg == "--create":
create_portals = True
else:
limit = int(arg)
threads = await evt.sender.fetchThreads(limit=limit, thread_location=ThreadLocation.INBOX)
ups = DBUserPortal.all(evt.sender.fbid)
for thread in threads:
portal = po.Portal.get_by_thread(thread, evt.sender.fbid)
if create_portals:
await portal.create_matrix_room(evt.sender, thread)
else:
await evt.sender._add_community(ups.get(portal.fbid, None), None, portal, None)
if contacts:
await evt.sender.sync_contacts()
await evt.reply("Syncing complete")
......@@ -37,6 +37,7 @@ class Config(BaseBridgeConfig):
copy("bridge.invite_own_puppet_to_pm")
copy("bridge.sync_with_custom_puppets")
copy("bridge.presence")
copy("bridge.update_avatar_initial_sync")
copy_dict("bridge.permissions")
......
......@@ -13,9 +13,9 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from typing import Dict
from typing import Dict, Optional
from sqlalchemy import Column, String, Boolean, ForeignKeyConstraint
from sqlalchemy import Column, String, Boolean, ForeignKeyConstraint, and_
from sqlalchemy.sql import expression
from mautrix.bridge.db.base import Base
......@@ -36,3 +36,8 @@ class UserPortal(Base):
@classmethod
def all(cls, user: str) -> Dict[str, 'UserPortal']:
return {up.portal: up for up in cls._select_all(cls.c.user == user)}
@classmethod
def get(cls, user: str, portal: str, portal_receiver: str) -> Optional['UserPortal']:
return cls._select_one_or_none(and_(cls.c.user == user, cls.c.portal == portal,
cls.c.portal_receiver == portal_receiver))
......@@ -235,11 +235,22 @@ class Portal:
async def _update_matrix_room(self, source: 'u.User',
info: Optional[ThreadClass] = None) -> None:
await self.main_intent.invite_user(self.mxid, source.mxid)
await self.main_intent.invite_user(self.mxid, source.mxid, check_cache=True)
puppet = p.Puppet.get_by_custom_mxid(source.mxid)
if puppet:
await puppet.intent.ensure_joined(self.mxid)
await self.update_info(source, info)
up = DBUserPortal.get(source.fbid, self.fbid, self.fb_receiver)
if not up:
in_community = await source._community_helper.add_room(source._community_id, self.mxid)
DBUserPortal(user=source.fbid, portal=self.fbid, portal_receiver=self.fb_receiver,
in_community=in_community).insert()
elif not up.in_community:
in_community = await source._community_helper.add_room(source._community_id, self.mxid)
up.edit(in_community=in_community)
async def create_matrix_room(self, source: 'u.User', info: Optional[ThreadClass] = None
) -> Optional[RoomID]:
if self.mxid:
......
......@@ -144,14 +144,14 @@ class Puppet(CustomPuppetMixin):
# region User info updating
async def update_info(self, source: Optional['u.User'] = None, info: Optional[FBUser] = None
) -> 'Puppet':
async def update_info(self, source: Optional['u.User'] = None, info: Optional[FBUser] = None,
update_avatar: bool = True) -> 'Puppet':
if not info:
info = (await source.fetchUserInfo(self.fbid))[self.fbid]
try:
changed = any(await asyncio.gather(self._update_name(info),
self._update_photo(info.photo),
loop=self.loop))
changed = await self._update_name(info)
if update_avatar:
changed = await self._update_photo(info.photo) or changed
if changed:
self.save()
except Exception:
......
......@@ -220,9 +220,10 @@ class User(Client):
users = await self.fetchAllUsers()
self.log.debug(f"Fetched {len(users)} contacts")
contacts = DBContact.all(self.fbid)
update_avatars = config["bridge.update_avatar_initial_sync"]
for user in users:
puppet = pu.Puppet.get_by_fbid(user.uid, create=True)
await puppet.update_info(self, user)
await puppet.update_info(self, user, update_avatar=update_avatars)
await self._add_community_puppet(contacts.get(puppet.fbid, None), puppet)
except Exception:
self.log.exception("Failed to sync contacts")
......
......@@ -23,7 +23,7 @@ setuptools.setup(
install_requires=[
"aiohttp>=3.0.1,<4",
"mautrix>=0.4.0.dev62,<0.5.0",
"mautrix>=0.4.0.dev64,<0.5.0",
"ruamel.yaml>=0.15.94,<0.17",
"commonmark>=0.8,<0.10",
"python-magic>=0.4,<0.5",
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment