fix(userbot): presence, story and profile history toggles of the capture policy take effect for each user peer
This commit is contained in:
1 parent
f32b772ddc
commit
92e5e737d2
10 files changed
+100
-25
No files matched your search
@@ -13,18 +13,19 @@ async def on_user_status(client: PyroClient, user: User) -> None:
|
|||||||
ctx = client.capture
|
ctx = client.capture
|
||||||
if ctx is None or user.status is None:
|
if ctx is None or user.status is None:
|
||||||
return
|
return
|
||||||
await repository.insert_status(
|
if ctx.resolve_peer(user.id, is_bot=bool(user.is_bot)).presence:
|
||||||
ctx.pool,
|
await repository.insert_status(
|
||||||
ctx.account_id,
|
ctx.pool,
|
||||||
user.id,
|
ctx.account_id,
|
||||||
datetime.now(UTC),
|
user.id,
|
||||||
user.status.name.lower(),
|
datetime.now(UTC),
|
||||||
user.last_online_date,
|
user.status.name.lower(),
|
||||||
user.next_offline_date,
|
user.last_online_date,
|
||||||
raw_json(user.raw),
|
user.next_offline_date,
|
||||||
)
|
raw_json(user.raw),
|
||||||
|
)
|
||||||
|
await notify_bg_event(ctx.pool, "presence", ctx.account_id, chat_id=user.id)
|
||||||
await ctx.watches.on_status(user.id, is_online=user.status.name.lower() == "online")
|
await ctx.watches.on_status(user.id, is_online=user.status.name.lower() == "online")
|
||||||
await notify_bg_event(ctx.pool, "presence", ctx.account_id, chat_id=user.id)
|
|
||||||
|
|
||||||
|
|
||||||
handlers = on_user_status.handlers # ty: ignore[unresolved-attribute]
|
handlers = on_user_status.handlers # ty: ignore[unresolved-attribute]
|
||||||
@@ -25,8 +25,14 @@ async def _handle_user(
|
|||||||
current = await get_peer(ctx.pool, ctx.account_id, update.user_id)
|
current = await get_peer(ctx.pool, ctx.account_id, update.user_id)
|
||||||
if current == fields:
|
if current == fields:
|
||||||
return
|
return
|
||||||
|
is_bot = bool(getattr(raw_user, "bot", False))
|
||||||
await write_profile(
|
await write_profile(
|
||||||
ctx.pool, ctx.account_id, update.user_id, fields, raw_json(raw_user)
|
ctx.pool,
|
||||||
|
ctx.account_id,
|
||||||
|
update.user_id,
|
||||||
|
fields,
|
||||||
|
raw_json(raw_user),
|
||||||
|
history=ctx.resolve_peer(update.user_id, is_bot=is_bot).profile_history,
|
||||||
)
|
)
|
||||||
changed_photo = current is None or current.photo_unique_id != photo_unique_id
|
changed_photo = current is None or current.photo_unique_id != photo_unique_id
|
||||||
if photo_file_id and photo_unique_id and changed_photo:
|
if photo_file_id and photo_unique_id and changed_photo:
|
||||||
@@ -51,7 +57,14 @@ async def _merge_partial(
|
|||||||
merged = replace(current or ProfileFields(), **overrides)
|
merged = replace(current or ProfileFields(), **overrides)
|
||||||
if merged == current:
|
if merged == current:
|
||||||
return
|
return
|
||||||
await write_profile(ctx.pool, ctx.account_id, peer_id, merged, raw_str)
|
await write_profile(
|
||||||
|
ctx.pool,
|
||||||
|
ctx.account_id,
|
||||||
|
peer_id,
|
||||||
|
merged,
|
||||||
|
raw_str,
|
||||||
|
history=ctx.resolve_peer(peer_id).profile_history,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def handle(
|
async def handle(
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
from pyrogram.types import Story
|
from pyrogram.types import Story
|
||||||
|
|
||||||
from userbot.modules.client import PyroClient
|
from userbot.modules.client import PyroClient
|
||||||
from userbot.modules.stories.service import save_story
|
from userbot.modules.stories.service import save_story, story_peer_id
|
||||||
|
|
||||||
|
|
||||||
@PyroClient.on_story()
|
@PyroClient.on_story()
|
||||||
async def on_story(client: PyroClient, story: Story) -> None:
|
async def on_story(client: PyroClient, story: Story) -> None:
|
||||||
if client.capture is None:
|
ctx = client.capture
|
||||||
|
if ctx is None:
|
||||||
return
|
return
|
||||||
await save_story(client, client.capture, story)
|
peer_id = story_peer_id(story)
|
||||||
|
is_bot = bool(story.from_user and story.from_user.is_bot)
|
||||||
|
if peer_id > 0 and not ctx.resolve_peer(peer_id, is_bot=is_bot).stories:
|
||||||
|
return
|
||||||
|
await save_story(client, ctx, story)
|
||||||
|
|
||||||
|
|
||||||
handlers = on_story.handlers # ty: ignore[unresolved-attribute]
|
handlers = on_story.handlers # ty: ignore[unresolved-attribute]
|
||||||
@@ -6,7 +6,7 @@ from userbot.modules.capture.pending import PendingDeletes
|
|||||||
from userbot.modules.contacts import ContactCache
|
from userbot.modules.contacts import ContactCache
|
||||||
from userbot.modules.folders import FolderCache
|
from userbot.modules.folders import FolderCache
|
||||||
from userbot.modules.watches import WatchCache
|
from userbot.modules.watches import WatchCache
|
||||||
from utils.policy.models import CaptureToggles, ChatMeta, PolicySet
|
from utils.policy.models import CaptureToggles, ChatKind, ChatMeta, PolicySet
|
||||||
from utils.policy.repository import load_policy_set
|
from utils.policy.repository import load_policy_set
|
||||||
from utils.policy.resolver import resolve
|
from utils.policy.resolver import resolve
|
||||||
from utils.storage import ContentAddressedStorage
|
from utils.storage import ContentAddressedStorage
|
||||||
@@ -38,6 +38,16 @@ class CaptureContext:
|
|||||||
def resolve(self, chat: ChatMeta) -> CaptureToggles:
|
def resolve(self, chat: ChatMeta) -> CaptureToggles:
|
||||||
return resolve(chat, self.folders.folders, self.policies)
|
return resolve(chat, self.folders.folders, self.policies)
|
||||||
|
|
||||||
|
def resolve_peer(self, peer_id: int, *, is_bot: bool = False) -> CaptureToggles:
|
||||||
|
return self.resolve(
|
||||||
|
ChatMeta(
|
||||||
|
chat_id=peer_id,
|
||||||
|
kind=ChatKind.DM,
|
||||||
|
is_bot=is_bot,
|
||||||
|
is_contact=peer_id in self.contacts.ids,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def build_capture_context(
|
async def build_capture_context(
|
||||||
client: Client,
|
client: Client,
|
||||||
|
|||||||
@@ -58,7 +58,14 @@ async def _capture_peer(message: Message, ctx: CaptureContext) -> None:
|
|||||||
fields, photo_file_id, photo_unique_id = snapshot_from_high_level(user)
|
fields, photo_file_id, photo_unique_id = snapshot_from_high_level(user)
|
||||||
if not await ctx.peer_identity.changed(ctx.pool, ctx.account_id, user.id, fields):
|
if not await ctx.peer_identity.changed(ctx.pool, ctx.account_id, user.id, fields):
|
||||||
return
|
return
|
||||||
await write_profile(ctx.pool, ctx.account_id, user.id, fields, raw_json(user))
|
await write_profile(
|
||||||
|
ctx.pool,
|
||||||
|
ctx.account_id,
|
||||||
|
user.id,
|
||||||
|
fields,
|
||||||
|
raw_json(user),
|
||||||
|
history=ctx.resolve_peer(user.id, is_bot=bool(user.is_bot)).profile_history,
|
||||||
|
)
|
||||||
if photo_file_id and photo_unique_id:
|
if photo_file_id and photo_unique_id:
|
||||||
from userbot.modules.avatars import note_avatar # noqa: PLC0415
|
from userbot.modules.avatars import note_avatar # noqa: PLC0415
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,14 @@ LIMIT 100
|
|||||||
|
|
||||||
async def _save_user(ctx: CaptureContext, user: User) -> None:
|
async def _save_user(ctx: CaptureContext, user: User) -> None:
|
||||||
fields, photo_file_id, photo_unique_id = snapshot_from_high_level(user)
|
fields, photo_file_id, photo_unique_id = snapshot_from_high_level(user)
|
||||||
await write_profile(ctx.pool, ctx.account_id, user.id, fields, raw_json(user))
|
await write_profile(
|
||||||
|
ctx.pool,
|
||||||
|
ctx.account_id,
|
||||||
|
user.id,
|
||||||
|
fields,
|
||||||
|
raw_json(user),
|
||||||
|
history=ctx.resolve_peer(user.id, is_bot=bool(user.is_bot)).profile_history,
|
||||||
|
)
|
||||||
if photo_file_id and photo_unique_id:
|
if photo_file_id and photo_unique_id:
|
||||||
await note_avatar(
|
await note_avatar(
|
||||||
ctx.pool, ctx.account_id, user.id, "peer", photo_unique_id, photo_file_id
|
ctx.pool, ctx.account_id, user.id, "peer", photo_unique_id, photo_file_id
|
||||||
|
|||||||
@@ -22,7 +22,16 @@ async def sync_contacts(ctx: JobContext) -> None:
|
|||||||
if not isinstance(user, User):
|
if not isinstance(user, User):
|
||||||
continue
|
continue
|
||||||
fields, photo_file_id, photo_unique_id = snapshot_from_high_level(user)
|
fields, photo_file_id, photo_unique_id = snapshot_from_high_level(user)
|
||||||
await write_profile(ctx.pool, ctx.account_id, user.id, fields, raw_json(user))
|
await write_profile(
|
||||||
|
ctx.pool,
|
||||||
|
ctx.account_id,
|
||||||
|
user.id,
|
||||||
|
fields,
|
||||||
|
raw_json(user),
|
||||||
|
history=capture.resolve_peer(
|
||||||
|
user.id, is_bot=bool(user.is_bot)
|
||||||
|
).profile_history,
|
||||||
|
)
|
||||||
if photo_file_id and photo_unique_id:
|
if photo_file_id and photo_unique_id:
|
||||||
await note_avatar(
|
await note_avatar(
|
||||||
ctx.pool,
|
ctx.pool,
|
||||||
|
|||||||
@@ -34,7 +34,14 @@ async def _enrich_users(client: Client, ctx: CaptureContext, ids: list[int]) ->
|
|||||||
continue
|
continue
|
||||||
fields, photo_file_id, photo_unique_id = snapshot_from_high_level(user)
|
fields, photo_file_id, photo_unique_id = snapshot_from_high_level(user)
|
||||||
await write_profile(
|
await write_profile(
|
||||||
ctx.pool, ctx.account_id, user.id, fields, raw_json(user)
|
ctx.pool,
|
||||||
|
ctx.account_id,
|
||||||
|
user.id,
|
||||||
|
fields,
|
||||||
|
raw_json(user),
|
||||||
|
history=ctx.resolve_peer(
|
||||||
|
user.id, is_bot=bool(user.is_bot)
|
||||||
|
).profile_history,
|
||||||
)
|
)
|
||||||
if photo_file_id and photo_unique_id:
|
if photo_file_id and photo_unique_id:
|
||||||
await note_avatar(
|
await note_avatar(
|
||||||
|
|||||||
@@ -49,8 +49,14 @@ async def get_peer(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def write_profile(
|
async def write_profile( # noqa: PLR0913
|
||||||
pool: asyncpg.Pool, account_id: int, peer_id: int, fields: ProfileFields, raw: str
|
pool: asyncpg.Pool,
|
||||||
|
account_id: int,
|
||||||
|
peer_id: int,
|
||||||
|
fields: ProfileFields,
|
||||||
|
raw: str,
|
||||||
|
*,
|
||||||
|
history: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
args = (
|
args = (
|
||||||
fields.first_name,
|
fields.first_name,
|
||||||
@@ -63,4 +69,5 @@ async def write_profile(
|
|||||||
)
|
)
|
||||||
async with pool.acquire() as conn, conn.transaction():
|
async with pool.acquire() as conn, conn.transaction():
|
||||||
await conn.execute(_UPSERT_PEER, account_id, peer_id, *args)
|
await conn.execute(_UPSERT_PEER, account_id, peer_id, *args)
|
||||||
await conn.execute(_INSERT_HISTORY, account_id, peer_id, *args)
|
if history:
|
||||||
|
await conn.execute(_INSERT_HISTORY, account_id, peer_id, *args)
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
from datetime import UTC, datetime
|
from datetime import UTC, datetime
|
||||||
|
|
||||||
|
from pyrogram.enums import ChatType
|
||||||
from pyrogram.types import Chat
|
from pyrogram.types import Chat
|
||||||
|
|
||||||
from userbot.modules.avatars import note_avatar
|
from userbot.modules.avatars import note_avatar
|
||||||
@@ -13,7 +14,15 @@ from userbot.modules.raw_json import raw_json
|
|||||||
async def save_private(ctx: CaptureContext, chat: Chat) -> bool:
|
async def save_private(ctx: CaptureContext, chat: Chat) -> bool:
|
||||||
chat_id = chat.id or 0
|
chat_id = chat.id or 0
|
||||||
fields, photo_file_id, photo_unique_id = snapshot_from_chat(chat)
|
fields, photo_file_id, photo_unique_id = snapshot_from_chat(chat)
|
||||||
await write_profile(ctx.pool, ctx.account_id, chat_id, fields, raw_json(chat))
|
is_bot = chat.type is ChatType.BOT
|
||||||
|
await write_profile(
|
||||||
|
ctx.pool,
|
||||||
|
ctx.account_id,
|
||||||
|
chat_id,
|
||||||
|
fields,
|
||||||
|
raw_json(chat),
|
||||||
|
history=ctx.resolve_peer(chat_id, is_bot=is_bot).profile_history,
|
||||||
|
)
|
||||||
if photo_file_id and photo_unique_id:
|
if photo_file_id and photo_unique_id:
|
||||||
await note_avatar(
|
await note_avatar(
|
||||||
ctx.pool, ctx.account_id, chat_id, "peer", photo_unique_id, photo_file_id
|
ctx.pool, ctx.account_id, chat_id, "peer", photo_unique_id, photo_file_id
|
||||||
|
|||||||
Reference in new issue
Block a user