Skip to content

Commit a4ee995

Browse files
authored
Vk callback (#23)
## Изменения Добавил возможность читать сообщения от ВК ## Детали Для добавления ВК группы нужно создать ее через АПИ, передав секретный ключ, после чего сохранить настройки в группе в интерфейсе ВК ## Check-List <!-- Проставьте x в квадратные скобки в нужных пунктах. Example: [x] --> - [x] Вы проверили свой код перед отправкой запроса? - [ ] Вы написали тесты к реализованным функциям? - [x] Вы не забыли применить форматирование `black` и `isort` для _Back-End_ или `Prettier` для _Front-End_?
1 parent d0b645b commit a4ee995

10 files changed

Lines changed: 142 additions & 4 deletions

File tree

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""vk
2+
3+
Revision ID: 9d98c1e9c864
4+
Revises: 57c72962d2b4
5+
Create Date: 2023-08-19 15:53:19.787309
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
11+
12+
# revision identifiers, used by Alembic.
13+
revision = '9d98c1e9c864'
14+
down_revision = '57c72962d2b4'
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
op.create_table('vk_groups',
21+
sa.Column('id', sa.Integer(), nullable=False),
22+
sa.Column('group_id', sa.Integer(), nullable=False),
23+
sa.Column('confirmation_token', sa.String(), nullable=False),
24+
sa.Column('secret_key', sa.String(), nullable=False),
25+
sa.Column('create_ts', sa.DateTime(), nullable=False),
26+
sa.Column('update_ts', sa.DateTime(), nullable=False),
27+
sa.PrimaryKeyConstraint('id')
28+
)
29+
30+
31+
def downgrade():
32+
op.drop_table('vk_groups')

social/handlers_github/profcomff_issues.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def issue_opened(event):
6767
projectId=PROJECT_NODE_ID,
6868
itemId=project_item_id,
6969
fieldId=DEADLINE_FIELD_NODE_ID,
70-
newDate=new_deadline_date
70+
newDate=new_deadline_date,
7171
)
7272
logging.debug("Deadline change response: %s", r)
7373

@@ -81,6 +81,6 @@ def issue_opened(event):
8181
projectId=PROJECT_NODE_ID,
8282
itemId=project_item_id,
8383
fieldId=TAKEN_FIELD_NODE_ID,
84-
newDate=new_taken_date
84+
newDate=new_taken_date,
8585
)
8686
logging.debug("Taken change response: %s", r)

social/handlers_telegram/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def get_application():
2525

2626
# Хэндлеры конкретных чатов
2727
register_handlers(app)
28-
28+
2929
return app
3030

3131

social/handlers_telegram/handlers_viribus.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
Приятно познакомиться, [{name}](tg://user?id={id})! Мы здесь, чтобы обсуждать всё, что связано с IT.
6565
6666
Какие темы в IT тебя больше всего интересуют и где ты узнал(а) о нас?
67-
"""
67+
""",
6868
]
6969

7070

social/models/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from .vk import VkGroups
2+
from .webhook_storage import WebhookStorage
3+
4+
5+
__all__ = ['WebhookStorage', 'VkGroups']

social/models/vk.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from datetime import datetime
2+
3+
import sqlalchemy as sa
4+
from sqlalchemy.orm import Mapped, mapped_column
5+
6+
from .base import Base
7+
8+
9+
class VkGroups(Base):
10+
id: Mapped[int] = mapped_column(sa.Integer, primary_key=True)
11+
group_id: Mapped[int] = mapped_column(sa.Integer)
12+
confirmation_token: Mapped[str] = mapped_column(sa.String)
13+
secret_key: Mapped[str] = mapped_column(sa.String)
14+
create_ts: Mapped[datetime] = mapped_column(sa.DateTime, default=datetime.utcnow)
15+
update_ts: Mapped[datetime] = mapped_column(sa.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

social/models/webhook_storage.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
class WebhookSystems(str, Enum):
1010
TELEGRAM = 'telegram'
1111
GITHUB = 'github'
12+
VK = 'vk'
1213

1314

1415
class WebhookStorage(Base):

social/routes/base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from .github import router as github_rourer
1010
from .telegram import router as telegram_rourer
11+
from .vk import router as vk_rourer
1112

1213

1314
settings = get_settings()
@@ -52,3 +53,4 @@ async def shutdown():
5253

5354
app.include_router(github_rourer)
5455
app.include_router(telegram_rourer)
56+
app.include_router(vk_rourer)

social/routes/vk.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import logging
2+
3+
from auth_lib.fastapi import UnionAuth
4+
from fastapi import APIRouter, Depends, Request
5+
from fastapi.responses import PlainTextResponse
6+
from fastapi_sqlalchemy import db
7+
from pydantic import BaseModel, ConfigDict
8+
9+
from social.handlers_telegram import get_application
10+
from social.models.vk import VkGroups
11+
from social.models.webhook_storage import WebhookStorage, WebhookSystems
12+
from social.settings import get_settings
13+
from social.utils.string import random_string
14+
15+
16+
router = APIRouter(prefix="/vk", tags=['vk'])
17+
settings = get_settings()
18+
logger = logging.getLogger(__name__)
19+
application = get_application()
20+
21+
22+
class VkGroupCreate(BaseModel):
23+
confirmation_token: str
24+
change_secret_key: bool = False
25+
26+
27+
class VkGroupCreateResponse(BaseModel):
28+
group_id: int
29+
secret_key: str
30+
31+
model_config = ConfigDict(from_attributes=True)
32+
33+
34+
@router.post('', tags=["webhooks"])
35+
async def vk_webhook(request: Request):
36+
"""Принимает любой POST запрос от VK"""
37+
request_data = await request.json()
38+
logger.debug(request_data)
39+
group_id = request_data["group_id"] # Fail if no group
40+
group = db.session.query(VkGroups).where(VkGroups.group_id == group_id).one() # Fail if no settings
41+
42+
# Проверка на создание нового вебхука со страничка ВК
43+
if request_data.get("type", "") == "confirmation":
44+
return PlainTextResponse(group.confirmation_token)
45+
46+
if request_data.get("secret") != group.secret_key:
47+
raise Exception("Not a valid secret")
48+
49+
db.session.add(
50+
WebhookStorage(
51+
system=WebhookSystems.VK,
52+
message=request_data,
53+
)
54+
)
55+
db.session.commit()
56+
57+
return
58+
59+
60+
@router.put('/{group_id}')
61+
def create_or_replace_group(
62+
group_id: int, group_info: VkGroupCreate, _=Depends(UnionAuth(["social.vk_group.create"]))
63+
) -> VkGroupCreateResponse:
64+
group = db.session.query(VkGroups).where(VkGroups.group_id == group_id).one_or_none()
65+
if group is None:
66+
group = VkGroups()
67+
db.session.add(group)
68+
group.group_id = group_id
69+
group.secret_key = random_string(32)
70+
71+
if group_info.change_secret_key:
72+
group.secret_key = random_string(32)
73+
74+
group.confirmation_token = group_info.confirmation_token
75+
76+
db.session.commit()
77+
return group

social/utils/string.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import random
2+
import string
3+
4+
5+
def random_string(N: int):
6+
return ''.join(random.choices(string.ascii_uppercase + string.digits, k=N))

0 commit comments

Comments
 (0)