feat(bot): Коммит — создание, замена и удаление файлов, черновик
- новый файл: имя → содержимое текстом (```-обёртка снимается) или документом - новая папка (виртуальная, пока в ней нет файлов), замена с diff +N/−M, удаление - валидация: имя, ≤ 100 КБ, UTF-8, без NUL; .py — ast.parse с выбором «исправить / всё равно»; .sourcecraft/, .tgit/, ruff.toml из бота не меняются - DraftService: черновик в БД, 24 ч, ≤ 50 изменений; удаление нового файла убирает его из черновика - дерево показывает черновик поверх репозитория: 🆕 / ✏️ / 🗑, размер — как будет после пуша - экран черновика (A/M/D) с «↩️ убрать» Refs #26 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+22
-5
@@ -7,9 +7,9 @@ from typing import Any
|
||||
|
||||
from aiogram import Bot, Dispatcher
|
||||
from aiogram.client.session.base import BaseSession
|
||||
from aiogram.methods import EditMessageText, GetMe, SendMessage, SendPhoto, TelegramMethod
|
||||
from aiogram.methods import EditMessageText, GetFile, GetMe, SendMessage, SendPhoto, TelegramMethod
|
||||
from aiogram.methods.base import TelegramType
|
||||
from aiogram.types import Chat, Message, Update, User
|
||||
from aiogram.types import Chat, File, Message, Update, User
|
||||
|
||||
BOT_TOKEN = "42:TEST-TOKEN"
|
||||
|
||||
@@ -19,6 +19,7 @@ class FakeSession(BaseSession):
|
||||
super().__init__()
|
||||
self.requests: list[TelegramMethod[Any]] = []
|
||||
self._ids = count(1000)
|
||||
self.files: dict[str, bytes] = {} # file_id -> content, for documents users "upload"
|
||||
|
||||
async def make_request(
|
||||
self,
|
||||
@@ -27,6 +28,10 @@ class FakeSession(BaseSession):
|
||||
timeout: int | None = None, # noqa: ASYNC109 - signature fixed by aiogram BaseSession
|
||||
) -> TelegramType:
|
||||
self.requests.append(method)
|
||||
if isinstance(method, GetFile):
|
||||
return File( # type: ignore[return-value]
|
||||
file_id=method.file_id, file_unique_id=method.file_id, file_path=f"documents/{method.file_id}"
|
||||
)
|
||||
if isinstance(method, GetMe):
|
||||
return User(id=42, is_bot=True, first_name="tgit", username="tgit_test_bot") # type: ignore[return-value]
|
||||
if isinstance(method, SendPhoto):
|
||||
@@ -54,9 +59,9 @@ class FakeSession(BaseSession):
|
||||
timeout: int = 30, # noqa: ASYNC109 - signature fixed by aiogram BaseSession
|
||||
chunk_size: int = 65536,
|
||||
raise_for_status: bool = True,
|
||||
) -> AsyncGenerator[bytes, None]: # pragma: no cover - not used
|
||||
raise NotImplementedError
|
||||
yield b""
|
||||
) -> AsyncGenerator[bytes, None]:
|
||||
file_id = url.rsplit("/", 1)[-1]
|
||||
yield self.files[file_id]
|
||||
|
||||
async def close(self) -> None:
|
||||
pass
|
||||
@@ -92,6 +97,18 @@ class TgClient:
|
||||
message["entities"] = [{"type": "bot_command", "offset": 0, "length": len(cmd)}]
|
||||
await self._feed({"message": message})
|
||||
|
||||
async def send_document(self, tg_id: int, name: str, content: bytes) -> None:
|
||||
file_id = f"doc{next(self._message_ids)}"
|
||||
self.session.files[file_id] = content
|
||||
message = {
|
||||
"message_id": next(self._message_ids),
|
||||
"date": int(datetime.now(UTC).timestamp()),
|
||||
"chat": {"id": tg_id, "type": "private"},
|
||||
"from": self.user(tg_id),
|
||||
"document": {"file_id": file_id, "file_unique_id": file_id, "file_name": name, "file_size": len(content)},
|
||||
}
|
||||
await self._feed({"message": message})
|
||||
|
||||
async def press(self, tg_id: int, data: str, message_text: str = "section") -> None:
|
||||
callback = {
|
||||
"id": str(next(self._update_ids)),
|
||||
|
||||
Reference in New Issue
Block a user