fix(backend): group title changes found by enrichment are recorded, enrichment and syncs skip unchanged profiles
This commit is contained in:
1 parent
efc431c969
commit
aa41bbbc74
6 files changed
+77
-110
No files matched your search
@@ -89,17 +89,15 @@ async def _capture_chat(message: Message, ctx: CaptureContext) -> None:
|
|||||||
meta = (chat.title, photo_unique_id)
|
meta = (chat.title, photo_unique_id)
|
||||||
if not await ctx.chat_meta.changed(ctx.pool, ctx.account_id, chat.id, meta):
|
if not await ctx.chat_meta.changed(ctx.pool, ctx.account_id, chat.id, meta):
|
||||||
return
|
return
|
||||||
from userbot.modules.groups.repository import insert_chat_history # noqa: PLC0415
|
from userbot.modules.groups.repository import record_chat_meta # noqa: PLC0415
|
||||||
|
|
||||||
await insert_chat_history(
|
await record_chat_meta(
|
||||||
ctx.pool,
|
ctx.pool,
|
||||||
ctx.account_id,
|
ctx.account_id,
|
||||||
chat.id,
|
chat.id,
|
||||||
message.id,
|
message.id,
|
||||||
"meta",
|
|
||||||
chat.title,
|
chat.title,
|
||||||
photo_unique_id,
|
photo_unique_id,
|
||||||
None,
|
|
||||||
message.date,
|
message.date,
|
||||||
raw_json(message),
|
raw_json(message),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,7 +7,23 @@ INSERT INTO chat_history
|
|||||||
(account_id, chat_id, message_id, event, title, photo_unique_id, actor_id,
|
(account_id, chat_id, message_id, event, title, photo_unique_id, actor_id,
|
||||||
ts, raw)
|
ts, raw)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::jsonb)
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::jsonb)
|
||||||
ON CONFLICT (account_id, chat_id, message_id) DO NOTHING
|
ON CONFLICT DO NOTHING
|
||||||
|
"""
|
||||||
|
|
||||||
|
_INSERT_CHAT_META = """
|
||||||
|
INSERT INTO chat_history
|
||||||
|
(account_id, chat_id, message_id, event, title, photo_unique_id, ts, raw)
|
||||||
|
SELECT $1, $2, $3, 'meta', $4::text, $5::text, $6, $7::jsonb
|
||||||
|
WHERE ($4::text, $5::text) IS DISTINCT FROM (
|
||||||
|
(SELECT title FROM chat_history
|
||||||
|
WHERE account_id = $1 AND chat_id = $2 AND event IN ('meta', 'title')
|
||||||
|
ORDER BY ts DESC LIMIT 1),
|
||||||
|
(SELECT photo_unique_id FROM chat_history
|
||||||
|
WHERE account_id = $1 AND chat_id = $2
|
||||||
|
AND event IN ('meta', 'photo', 'photo_deleted')
|
||||||
|
ORDER BY ts DESC LIMIT 1)
|
||||||
|
)
|
||||||
|
ON CONFLICT DO NOTHING
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_INSERT_MEMBERSHIP = """
|
_INSERT_MEMBERSHIP = """
|
||||||
@@ -19,13 +35,14 @@ ON CONFLICT (account_id, chat_id, message_id, user_id) DO NOTHING
|
|||||||
|
|
||||||
_LATEST_TITLE = """
|
_LATEST_TITLE = """
|
||||||
SELECT title FROM chat_history
|
SELECT title FROM chat_history
|
||||||
WHERE account_id = $1 AND chat_id = $2 AND title IS NOT NULL
|
WHERE account_id = $1 AND chat_id = $2 AND event IN ('meta', 'title')
|
||||||
ORDER BY ts DESC LIMIT 1
|
ORDER BY ts DESC LIMIT 1
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_LATEST_PHOTO = """
|
_LATEST_PHOTO = """
|
||||||
SELECT photo_unique_id FROM chat_history
|
SELECT photo_unique_id FROM chat_history
|
||||||
WHERE account_id = $1 AND chat_id = $2 AND photo_unique_id IS NOT NULL
|
WHERE account_id = $1 AND chat_id = $2
|
||||||
|
AND event IN ('meta', 'photo', 'photo_deleted')
|
||||||
ORDER BY ts DESC LIMIT 1
|
ORDER BY ts DESC LIMIT 1
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -64,6 +81,29 @@ async def insert_chat_history( # noqa: PLR0913
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def record_chat_meta( # noqa: PLR0913
|
||||||
|
pool: asyncpg.Pool,
|
||||||
|
account_id: int,
|
||||||
|
chat_id: int,
|
||||||
|
message_id: int,
|
||||||
|
title: str | None,
|
||||||
|
photo_unique_id: str | None,
|
||||||
|
ts: datetime,
|
||||||
|
raw: str,
|
||||||
|
) -> bool:
|
||||||
|
status = await pool.execute(
|
||||||
|
_INSERT_CHAT_META,
|
||||||
|
account_id,
|
||||||
|
chat_id,
|
||||||
|
message_id,
|
||||||
|
title,
|
||||||
|
photo_unique_id,
|
||||||
|
ts,
|
||||||
|
raw,
|
||||||
|
)
|
||||||
|
return status == "INSERT 0 1"
|
||||||
|
|
||||||
|
|
||||||
async def insert_membership( # noqa: PLR0913
|
async def insert_membership( # noqa: PLR0913
|
||||||
pool: asyncpg.Pool,
|
pool: asyncpg.Pool,
|
||||||
account_id: int,
|
account_id: int,
|
||||||
|
|||||||
@@ -1,17 +1,11 @@
|
|||||||
from datetime import UTC, datetime
|
|
||||||
|
|
||||||
from pyrogram import Client
|
from pyrogram import Client
|
||||||
from pyrogram.errors import BadRequest, Forbidden
|
from pyrogram.errors import BadRequest, Forbidden
|
||||||
from pyrogram.types import User
|
from pyrogram.types import User
|
||||||
|
|
||||||
from userbot.modules.avatars import note_avatar
|
|
||||||
from userbot.modules.capture.context import CaptureContext
|
from userbot.modules.capture.context import CaptureContext
|
||||||
from userbot.modules.groups.repository import insert_chat_history
|
|
||||||
from userbot.modules.jobs.context import JobContext
|
from userbot.modules.jobs.context import JobContext
|
||||||
from userbot.modules.jobs.registry import register
|
from userbot.modules.jobs.registry import register
|
||||||
from userbot.modules.profiles.parse import snapshot_from_high_level
|
from userbot.modules.profiles.snapshots import save_group, save_user
|
||||||
from userbot.modules.profiles.repository import write_profile
|
|
||||||
from userbot.modules.raw_json import raw_json
|
|
||||||
|
|
||||||
MEMBER_CAP = 200
|
MEMBER_CAP = 200
|
||||||
|
|
||||||
@@ -25,52 +19,17 @@ LIMIT 100
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
async def _save_user(ctx: CaptureContext, user: User) -> None:
|
|
||||||
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),
|
|
||||||
history=ctx.resolve_peer(user.id, is_bot=bool(user.is_bot)).profile_history,
|
|
||||||
)
|
|
||||||
if photo_file_id and photo_unique_id:
|
|
||||||
await note_avatar(
|
|
||||||
ctx.pool, ctx.account_id, user.id, "peer", photo_unique_id, photo_file_id
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def _enrich_chat_meta(client: Client, ctx: CaptureContext, chat_id: int) -> None:
|
async def _enrich_chat_meta(client: Client, ctx: CaptureContext, chat_id: int) -> None:
|
||||||
chat = await client.get_chat(chat_id)
|
chat = await client.get_chat(chat_id)
|
||||||
if chat is None:
|
if chat is not None:
|
||||||
return
|
await save_group(ctx, chat)
|
||||||
photo = chat.photo
|
|
||||||
photo_unique_id = photo.big_photo_unique_id if photo else None
|
|
||||||
photo_file_id = photo.big_file_id if photo else None
|
|
||||||
await insert_chat_history(
|
|
||||||
ctx.pool,
|
|
||||||
ctx.account_id,
|
|
||||||
chat_id,
|
|
||||||
0,
|
|
||||||
"meta",
|
|
||||||
chat.title,
|
|
||||||
photo_unique_id,
|
|
||||||
None,
|
|
||||||
datetime.now(UTC),
|
|
||||||
raw_json(chat),
|
|
||||||
)
|
|
||||||
if photo_file_id and photo_unique_id:
|
|
||||||
await note_avatar(
|
|
||||||
ctx.pool, ctx.account_id, chat_id, "chat", photo_unique_id, photo_file_id
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def _enrich_members(client: Client, ctx: CaptureContext, chat_id: int) -> None:
|
async def _enrich_members(client: Client, ctx: CaptureContext, chat_id: int) -> None:
|
||||||
try:
|
try:
|
||||||
async for member in client.get_chat_members(chat_id, limit=MEMBER_CAP):
|
async for member in client.get_chat_members(chat_id, limit=MEMBER_CAP):
|
||||||
if isinstance(member.user, User):
|
if isinstance(member.user, User):
|
||||||
await _save_user(ctx, member.user)
|
await save_user(ctx, member.user)
|
||||||
except (BadRequest, Forbidden):
|
except (BadRequest, Forbidden):
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -96,7 +55,7 @@ async def _enrich_senders(client: Client, ctx: CaptureContext, chat_id: int) ->
|
|||||||
if not ids:
|
if not ids:
|
||||||
return
|
return
|
||||||
for user in await _fetch_users(client, ids):
|
for user in await _fetch_users(client, ids):
|
||||||
await _save_user(ctx, user)
|
await save_user(ctx, user)
|
||||||
|
|
||||||
|
|
||||||
@register("enrich_chat")
|
@register("enrich_chat")
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
from pyrogram.types import User
|
from pyrogram.types import User
|
||||||
|
|
||||||
from userbot.modules.avatars import note_avatar
|
|
||||||
from userbot.modules.jobs.context import JobContext
|
from userbot.modules.jobs.context import JobContext
|
||||||
from userbot.modules.jobs.registry import register
|
from userbot.modules.jobs.registry import register
|
||||||
from userbot.modules.profiles.parse import snapshot_from_high_level
|
from userbot.modules.profiles.snapshots import save_user
|
||||||
from userbot.modules.profiles.repository import write_profile
|
|
||||||
from userbot.modules.raw_json import raw_json
|
|
||||||
|
|
||||||
|
|
||||||
@register("sync_contacts")
|
@register("sync_contacts")
|
||||||
@@ -21,26 +18,7 @@ async def sync_contacts(ctx: JobContext) -> None:
|
|||||||
for user in contacts:
|
for user in contacts:
|
||||||
if not isinstance(user, User):
|
if not isinstance(user, User):
|
||||||
continue
|
continue
|
||||||
fields, photo_file_id, photo_unique_id = snapshot_from_high_level(user)
|
await save_user(capture, 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:
|
|
||||||
await note_avatar(
|
|
||||||
ctx.pool,
|
|
||||||
ctx.account_id,
|
|
||||||
user.id,
|
|
||||||
"peer",
|
|
||||||
photo_unique_id,
|
|
||||||
photo_file_id,
|
|
||||||
)
|
|
||||||
processed += 1
|
processed += 1
|
||||||
await capture.contacts.refresh()
|
await capture.contacts.refresh()
|
||||||
await ctx.report_progress({"processed": processed, "done": True})
|
await ctx.report_progress({"processed": processed, "done": True})
|
||||||
@@ -2,14 +2,10 @@ from pyrogram import Client
|
|||||||
from pyrogram.errors import BadRequest, Forbidden
|
from pyrogram.errors import BadRequest, Forbidden
|
||||||
from pyrogram.types import User
|
from pyrogram.types import User
|
||||||
|
|
||||||
from userbot.modules.avatars import note_avatar
|
|
||||||
from userbot.modules.capture.context import CaptureContext
|
from userbot.modules.capture.context import CaptureContext
|
||||||
from userbot.modules.jobs.context import JobContext
|
from userbot.modules.jobs.context import JobContext
|
||||||
from userbot.modules.jobs.registry import register
|
from userbot.modules.jobs.registry import register
|
||||||
from userbot.modules.profiles.parse import snapshot_from_high_level
|
from userbot.modules.profiles.snapshots import save_group, save_private, save_user
|
||||||
from userbot.modules.profiles.repository import write_profile
|
|
||||||
from userbot.modules.profiles.snapshots import save_group, save_private
|
|
||||||
from userbot.modules.raw_json import raw_json
|
|
||||||
from utils.logging import logger
|
from utils.logging import logger
|
||||||
|
|
||||||
SAVE_EVERY = 100
|
SAVE_EVERY = 100
|
||||||
@@ -30,28 +26,8 @@ async def _enrich_users(client: Client, ctx: CaptureContext, ids: list[int]) ->
|
|||||||
continue
|
continue
|
||||||
users = result if isinstance(result, list) else [result]
|
users = result if isinstance(result, list) else [result]
|
||||||
for user in users:
|
for user in users:
|
||||||
if not isinstance(user, User):
|
if isinstance(user, User):
|
||||||
continue
|
await save_user(ctx, 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),
|
|
||||||
history=ctx.resolve_peer(
|
|
||||||
user.id, is_bot=bool(user.is_bot)
|
|
||||||
).profile_history,
|
|
||||||
)
|
|
||||||
if photo_file_id and photo_unique_id:
|
|
||||||
await note_avatar(
|
|
||||||
ctx.pool,
|
|
||||||
ctx.account_id,
|
|
||||||
user.id,
|
|
||||||
"peer",
|
|
||||||
photo_unique_id,
|
|
||||||
photo_file_id,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@register("sync_dialogs")
|
@register("sync_dialogs")
|
||||||
|
|||||||
@@ -1,16 +1,34 @@
|
|||||||
from datetime import UTC, datetime
|
from datetime import UTC, datetime
|
||||||
|
|
||||||
from pyrogram.enums import ChatType
|
from pyrogram.enums import ChatType
|
||||||
from pyrogram.types import Chat
|
from pyrogram.types import Chat, User
|
||||||
|
|
||||||
from userbot.modules.avatars import note_avatar
|
from userbot.modules.avatars import note_avatar
|
||||||
from userbot.modules.capture.context import CaptureContext
|
from userbot.modules.capture.context import CaptureContext
|
||||||
from userbot.modules.groups.repository import insert_chat_history
|
from userbot.modules.groups.repository import record_chat_meta
|
||||||
from userbot.modules.profiles.parse import snapshot_from_chat
|
from userbot.modules.profiles.parse import snapshot_from_chat, snapshot_from_high_level
|
||||||
from userbot.modules.profiles.repository import write_profile
|
from userbot.modules.profiles.repository import write_profile
|
||||||
from userbot.modules.raw_json import raw_json
|
from userbot.modules.raw_json import raw_json
|
||||||
|
|
||||||
|
|
||||||
|
async def save_user(ctx: CaptureContext, user: User) -> None:
|
||||||
|
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):
|
||||||
|
return
|
||||||
|
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:
|
||||||
|
await note_avatar(
|
||||||
|
ctx.pool, ctx.account_id, user.id, "peer", photo_unique_id, photo_file_id
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
@@ -35,15 +53,13 @@ async def save_group(ctx: CaptureContext, chat: Chat) -> None:
|
|||||||
photo = chat.photo
|
photo = chat.photo
|
||||||
photo_unique_id = photo.big_photo_unique_id if photo else None
|
photo_unique_id = photo.big_photo_unique_id if photo else None
|
||||||
photo_file_id = photo.big_file_id if photo else None
|
photo_file_id = photo.big_file_id if photo else None
|
||||||
await insert_chat_history(
|
await record_chat_meta(
|
||||||
ctx.pool,
|
ctx.pool,
|
||||||
ctx.account_id,
|
ctx.account_id,
|
||||||
chat_id,
|
chat_id,
|
||||||
0,
|
0,
|
||||||
"meta",
|
|
||||||
chat.title,
|
chat.title,
|
||||||
photo_unique_id,
|
photo_unique_id,
|
||||||
None,
|
|
||||||
datetime.now(UTC),
|
datetime.now(UTC),
|
||||||
raw_json(chat),
|
raw_json(chat),
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in new issue
Block a user