Skip to content

Commit f660753

Browse files
authored
Tg group owner (#31)
## Изменения Добвалена возможность стать оунером группы
1 parent 6cb242f commit f660753

13 files changed

Lines changed: 213 additions & 31 deletions

File tree

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""Create group request
2+
3+
Revision ID: 27dda7e6236a
4+
Revises: 62addefd9655
5+
Create Date: 2024-04-15 03:59:03.133907
6+
7+
"""
8+
9+
import sqlalchemy as sa
10+
from alembic import op
11+
12+
13+
# revision identifiers, used by Alembic.
14+
revision = '27dda7e6236a'
15+
down_revision = '62addefd9655'
16+
branch_labels = None
17+
depends_on = None
18+
19+
20+
def upgrade():
21+
op.create_table(
22+
'create_group_request',
23+
sa.Column('id', sa.Integer(), nullable=False),
24+
sa.Column('secret_key', sa.String(), nullable=False),
25+
sa.Column('owner_id', sa.Integer(), nullable=False),
26+
sa.Column('mapped_group_id', sa.Integer(), nullable=True),
27+
sa.Column('create_ts', sa.DateTime(), nullable=False),
28+
sa.Column('valid_ts', sa.DateTime(), nullable=False),
29+
sa.ForeignKeyConstraint(
30+
['mapped_group_id'],
31+
['group.id'],
32+
),
33+
sa.PrimaryKeyConstraint('id'),
34+
)
35+
36+
37+
def downgrade():
38+
op.drop_table('create_group_request')

social/exceptions.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class SocialApiError(Exception):
2+
"""Корневая ошибка Social API"""
3+
4+
5+
class GroupRequestNotFound(SocialApiError):
6+
"""Не найдено запроса на создание группы"""
7+
8+
def __init__(self, user_id: int, secret_key: str, *args) -> None:
9+
self.user_id = user_id
10+
self.secret_key = secret_key
11+
super().__init__(*args)

social/handlers_telegram/base.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
from functools import lru_cache
33
from textwrap import dedent
44

5+
from fastapi_sqlalchemy import db
56
from telegram import Update
67
from telegram.ext import Application, CommandHandler, ContextTypes
78

89
from social.settings import get_settings
10+
from social.utils.telegram_groups import approve_telegram_group
911

1012
from .handlers_viribus import register_handlers
1113
from .utils import CustomContext
@@ -24,6 +26,7 @@ def get_application():
2426
logger.info("Telegram API initialized successfully")
2527
# Общие хэндлеры
2628
app.add_handler(CommandHandler(callback=send_help, command="help"))
29+
app.add_handler(CommandHandler(callback=validate_group, command="validate", has_args=1))
2730

2831
# Хэндлеры конкретных чатов
2932
register_handlers(app)
@@ -43,3 +46,11 @@ async def send_help(update: Update, context: CustomContext):
4346
),
4447
parse_mode='markdown',
4548
)
49+
50+
51+
async def validate_group(update: Update, context: CustomContext):
52+
logger.info("Validation message received")
53+
with db():
54+
approve_telegram_group(update)
55+
res = await update.effective_message.delete()
56+
logger.info(f"Validation message handled, delete status = {res}")

social/models/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
from .create_group_request import CreateGroupRequest
12
from .group import TelegramChannel, TelegramChat, VkChat, VkGroup
23
from .webhook_storage import WebhookStorage
34

45

5-
__all__ = ['WebhookStorage', 'TelegramChannel', 'TelegramChat', 'VkGroup', 'VkChat']
6+
__all__ = ['WebhookStorage', 'TelegramChannel', 'TelegramChat', 'VkGroup', 'VkChat', 'CreateGroupRequest']
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from datetime import UTC, datetime, timedelta
2+
3+
import sqlalchemy as sa
4+
from sqlalchemy.orm import Mapped, mapped_column, relationship
5+
6+
from social.utils.string import random_string
7+
8+
from .base import Base
9+
from .group import Group
10+
11+
12+
class CreateGroupRequest(Base):
13+
id: Mapped[int] = mapped_column(primary_key=True)
14+
secret_key: Mapped[str] = mapped_column(default=lambda: random_string(32))
15+
owner_id: Mapped[int]
16+
mapped_group_id: Mapped[int | None] = mapped_column(sa.ForeignKey("group.id"))
17+
18+
create_ts: Mapped[datetime] = mapped_column(default=lambda: datetime.now(UTC))
19+
valid_ts: Mapped[datetime] = mapped_column(default=lambda: datetime.now(UTC) + timedelta(days=1))
20+
21+
mapped_group: Mapped[Group | None] = relationship(Group)

social/models/group.py

Lines changed: 3 additions & 3 deletions
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 | None]
15+
last_active_ts: Mapped[datetime]
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))
@@ -44,7 +44,7 @@ class VkChat(Group):
4444

4545
class TelegramChannel(Group):
4646
id: Mapped[int] = mapped_column(sa.ForeignKey("group.id"), primary_key=True)
47-
channel_id: Mapped[int]
47+
channel_id: Mapped[int] = mapped_column(sa.BigInteger)
4848

4949
__mapper_args__ = {
5050
"polymorphic_identity": "tg_channel",
@@ -53,7 +53,7 @@ class TelegramChannel(Group):
5353

5454
class TelegramChat(Group):
5555
id: Mapped[int] = mapped_column(sa.ForeignKey("group.id"), primary_key=True)
56-
chat_id: Mapped[int]
56+
chat_id: Mapped[int] = mapped_column(sa.BigInteger)
5757

5858
__mapper_args__ = {
5959
"polymorphic_identity": "tg_chat",

social/routes/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import exceptions # noqa

social/routes/base.py

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

1111
from .discord import router as discord_router
1212
from .github import router as github_router
13+
from .group import router as group_router
1314
from .telegram import router as telegram_router
1415
from .vk import router as vk_router
1516

@@ -56,6 +57,7 @@ async def lifespan(app: FastAPI):
5657
)
5758

5859

60+
app.include_router(group_router)
5961
app.include_router(github_router)
6062
app.include_router(telegram_router)
6163
app.include_router(vk_router)

social/routes/exceptions.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from fastapi import Request
2+
from fastapi.responses import JSONResponse
3+
4+
from social.exceptions import GroupRequestNotFound
5+
6+
from .base import app
7+
8+
9+
@app.exception_handler(GroupRequestNotFound)
10+
def group_request_not_found(request: Request, exc: GroupRequestNotFound) -> JSONResponse:
11+
return JSONResponse(
12+
status_code=404,
13+
content={
14+
'details': 'Group request not found',
15+
'ru': 'Запрос на создание группы не найден',
16+
'user_id': exc.user_id,
17+
'secret_key': exc.secret_key,
18+
},
19+
)

social/routes/group.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import logging
2+
from datetime import UTC, datetime
3+
4+
from auth_lib.fastapi import UnionAuth
5+
from fastapi import APIRouter, Depends
6+
from fastapi_sqlalchemy import db
7+
from pydantic import BaseModel
8+
9+
from social.exceptions import GroupRequestNotFound
10+
from social.models.create_group_request import CreateGroupRequest
11+
from social.settings import get_settings
12+
13+
14+
router = APIRouter(prefix="/group", tags=['User defined groups'])
15+
settings = get_settings()
16+
logger = logging.getLogger(__name__)
17+
18+
19+
class GroupRequestGet(BaseModel):
20+
secret_key: str
21+
valid_ts: datetime
22+
23+
24+
class GroupGet(BaseModel):
25+
id: int
26+
27+
28+
@router.post('')
29+
def create_group_request(
30+
user: dict[str] = Depends(UnionAuth(["social.group.create"])),
31+
) -> GroupRequestGet:
32+
obj = CreateGroupRequest(owner_id=user.get("id"))
33+
db.session.add(obj)
34+
db.session.commit()
35+
return obj
36+
37+
38+
@router.get('')
39+
def validate_group_request(
40+
secret_key: str,
41+
user: dict[str] = Depends(UnionAuth(["social.group.create"])),
42+
) -> GroupGet | GroupRequestGet:
43+
obj = (
44+
db.session.query(CreateGroupRequest)
45+
.where(CreateGroupRequest.secret_key == secret_key, CreateGroupRequest.owner_id == user.get("id"))
46+
.one_or_none()
47+
)
48+
if obj is None or obj.valid_ts.replace(tzinfo=UTC) < datetime.now(UTC):
49+
raise GroupRequestNotFound(user_id=user.get("id"), secret_key=secret_key)
50+
51+
if obj.mapped_group_id is not None:
52+
return GroupGet.model_validate(obj.mapped_group, from_attributes=True)
53+
54+
return GroupRequestGet.model_validate(obj, from_attributes=True)

0 commit comments

Comments
 (0)