Skip to content

Commit 330337c

Browse files
committed
Approve VK
1 parent 3f138d5 commit 330337c

8 files changed

Lines changed: 115 additions & 27 deletions

File tree

.github/workflows/build_and_publish.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ jobs:
131131
--env DB_DSN='${{ secrets.DB_DSN }}' \
132132
--env AUTH_URL='https://api.profcomff.com/auth' \
133133
--env TELEGRAM_BOT_TOKEN='${{ secrets.TELEGRAM_BOT_TOKEN }}' \
134+
--env VK_BOT_GROUP_ID='{{ secrets.VK_BOT_GROUP_ID }}' \
135+
--env VK_BOT_TOKEN='{{ secrets.VK_BOT_TOKEN }}' \
134136
--env GITHUB_APP_ID='${{ secrets.GH_APP_ID }}' \
135137
--env GITHUB_PRIVATE_KEY='${{ secrets.GH_PRIVATE_KEY }}' \
136138
--env DISCORD_PUBLIC_KEY='${{ secrets.DISCORD_PUBLIC_KEY }}' \

social/handlers_vk/__init__.py

Whitespace-only changes.

social/handlers_vk/base.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import logging
2+
from collections.abc import Callable
3+
4+
from social.utils.events import EventProcessor
5+
from social.utils.vk_groups import approve_vk_chat
6+
7+
8+
logger = logging.getLogger(__name__)
9+
EVENT_PROCESSORS: list[EventProcessor] = []
10+
11+
12+
def event(**filters: str):
13+
"""Помечает функцию как обработчик событий, задает фильтры для запуска"""
14+
15+
def deco(func: Callable):
16+
EVENT_PROCESSORS.append(EventProcessor(filters, func))
17+
return func
18+
19+
return deco
20+
21+
22+
def process_event(event: dict):
23+
for processor in EVENT_PROCESSORS:
24+
if processor.check_and_process(event):
25+
break
26+
else:
27+
logger.debug("Event without processor")
28+
29+
30+
@event(
31+
type="message_new",
32+
object=lambda i: i.get("message", {}).get("text", "").startswith("/validate"),
33+
)
34+
def validate_group(event: dict):
35+
approve_vk_chat(event)

social/models/group.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class Group(Base):
1212
owner_id: Mapped[int | None]
1313

1414
is_deleted: Mapped[bool] = mapped_column(default=False)
15-
last_active_ts: Mapped[datetime]
15+
last_active_ts: Mapped[datetime] = mapped_column(default=lambda: datetime.now(UTC))
1616

1717
create_ts: Mapped[datetime] = mapped_column(default=lambda: datetime.now(UTC))
1818
update_ts: Mapped[datetime] = mapped_column(default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC))

social/routes/vk.py

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import logging
2-
from datetime import UTC, datetime
32

43
from auth_lib.fastapi import UnionAuth
5-
from fastapi import APIRouter, Depends, Request
4+
from fastapi import APIRouter, BackgroundTasks, Depends, Request
65
from fastapi.responses import PlainTextResponse
76
from fastapi_sqlalchemy import db
87
from pydantic import BaseModel, ConfigDict
98

10-
from social.models.group import VkChat, VkGroup
9+
from social.handlers_vk.base import process_event
10+
from social.models.group import VkGroup
1111
from social.models.webhook_storage import WebhookStorage, WebhookSystems
1212
from social.settings import get_settings
1313
from social.utils.string import random_string
14+
from social.utils.vk_groups import create_vk_chat
1415

1516

1617
router = APIRouter(prefix="/vk", tags=['vk'])
@@ -31,7 +32,7 @@ class VkGroupCreateResponse(BaseModel):
3132

3233

3334
@router.post('', tags=["webhooks"])
34-
async def vk_webhook(request: Request) -> str:
35+
async def vk_webhook(request: Request, background_tasks: BackgroundTasks) -> str:
3536
"""Принимает любой POST запрос от VK"""
3637
request_data = await request.json()
3738
logger.debug(request_data)
@@ -53,27 +54,8 @@ async def vk_webhook(request: Request) -> str:
5354
)
5455
db.session.commit()
5556

56-
if request_data.get("type") == "message_new":
57-
# Получение сообщения в чате ВК
58-
try:
59-
peer_id = request_data["object"]["message"]["peer_id"]
60-
obj = db.session.query(VkChat).where(VkChat.peer_id == peer_id).one_or_none()
61-
if obj is None:
62-
# Надо будет добавлять название группы
63-
# conversation = requests.post("https://api.vk.com/method/messages.getConversationsById", json={
64-
# "peer_ids": peer_id,
65-
# "group_id": 222099060,
66-
# "access_token": settings.VK_BOT_TOKEN,
67-
# "v": 5.199,
68-
# })
69-
# chat_title = conversation["response"]["items"][0]["chat_settings"]["title"]
70-
obj = VkChat(chat_id=peer_id)
71-
db.session.add(obj)
72-
obj.last_active_ts = datetime.now(UTC)
73-
db.session.commit()
74-
except Exception as exc:
75-
logger.exception(exc)
76-
57+
background_tasks.add_task(create_vk_chat, request_data)
58+
background_tasks.add_task(process_event, request_data)
7759
return PlainTextResponse('ok')
7860

7961

social/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class Settings(BaseSettings):
2020

2121
TELEGRAM_BOT_TOKEN: str | None = None
2222

23+
VK_BOT_GROUP_ID: int | None = None
2324
VK_BOT_TOKEN: str | None = None
2425

2526
GITHUB_APP_ID: int | None = None

social/utils/telegram_groups.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212

1313
def create_telegram_group(update: Update):
14+
"""Создает запись о телеграмм группе в внутренней БД приложения или возвращает существующий"""
1415
chat = update.effective_chat
1516
obj = None
1617
if chat.type in ['group', 'supergroup']:
@@ -33,6 +34,7 @@ def create_telegram_group(update: Update):
3334

3435

3536
def approve_telegram_group(update: Update):
37+
"""Если получено сообщение команды /validate, то за группой закрепляется владелец"""
3638
logger.debug("Validation started")
3739
group = create_telegram_group(update)
3840
text = update.effective_message.text
@@ -41,7 +43,7 @@ def approve_telegram_group(update: Update):
4143
return
4244
text = text.removeprefix('/validate').removeprefix('@ViribusSocialBot').strip()
4345
request = db.session.query(CreateGroupRequest).where(CreateGroupRequest.secret_key == text).one_or_none()
44-
request.mapped_group_id=group.id
46+
request.mapped_group_id = group.id
4547
group.owner_id = request.owner_id
4648
db.session.commit()
4749
logger.info("Telegram group %d validated (secret=%s)", group.id, text)

social/utils/vk_groups.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import logging
2+
from datetime import UTC, datetime
3+
4+
import requests
5+
from fastapi_sqlalchemy import db
6+
7+
from social.models import CreateGroupRequest, VkChat
8+
from social.settings import get_settings
9+
10+
11+
logger = logging.getLogger(__name__)
12+
settings = get_settings()
13+
14+
15+
def get_chat_name(peer_id):
16+
"""Получить название чата ВК"""
17+
conversation = requests.post(
18+
"https://api.vk.com/method/messages.getConversationsById",
19+
json={
20+
"peer_ids": peer_id,
21+
"group_id": settings.VK_BOT_GROUP_ID,
22+
"access_token": settings.VK_BOT_TOKEN,
23+
"v": 5.199,
24+
},
25+
)
26+
try:
27+
return conversation["response"]["items"][0]["chat_settings"]["title"]
28+
except Exception as exc:
29+
logger.exception(exc)
30+
return None
31+
32+
33+
def create_vk_chat(request_data: dict[str]):
34+
"""Создает запись о вк чате в внутренней БД приложения или возвращает существующий"""
35+
if (
36+
request_data.get("group_id") == settings.VK_BOT_GROUP_ID # peer_id чатов уникальные для каждого пользователя ВК
37+
and request_data.get("type") == "message_new"
38+
):
39+
# Получение сообщения в чате ВК
40+
try:
41+
peer_id = request_data["object"]["message"]["peer_id"]
42+
obj = db.session.query(VkChat).where(VkChat.peer_id == peer_id).one_or_none()
43+
if obj is None:
44+
obj = VkChat(peer_id=peer_id)
45+
db.session.add(obj)
46+
obj.last_active_ts = datetime.now(UTC)
47+
db.session.commit()
48+
except Exception as exc:
49+
logger.exception(exc)
50+
return obj
51+
return None
52+
53+
54+
def approve_vk_chat(request_data: dict[str]):
55+
"""Если получено сообщение команды /validate, то за группой закрепляется владелец"""
56+
logger.debug("Validation started")
57+
group = create_vk_chat(request_data)
58+
text = request_data.get("object", {}).get("message", {}).get("text", "").removeprefix("/validate").strip()
59+
if not text or not group or group.owner_id is not None:
60+
logger.error("Telegram group not validated (secret=%s, group=%s)", text, group)
61+
return
62+
request = db.session.query(CreateGroupRequest).where(CreateGroupRequest.secret_key == text).one_or_none()
63+
request.mapped_group_id = group.id
64+
group.owner_id = request.owner_id
65+
db.session.commit()
66+
logger.info("VK group %d validated (secret=%s)", group.id, text)

0 commit comments

Comments
 (0)