Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sync request via pybotx #43

Merged
merged 1 commit into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 18 additions & 48 deletions backend/app/api/endpoints/botx.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,74 +8,44 @@
Bot,
BotXMethodCallbackNotFoundError,
UnknownBotAccountError,
UnsupportedBotAPIVersionError,
UnverifiedRequestError,
build_bot_disabled_response,
build_command_accepted_response,
build_unverified_request_response,
)
from pybotx.constants import BOT_API_VERSION

from app.api.dependencies.bot import bot_dependency
from app.api.exceptions.botx import handle_exceptions
from app.logger import logger
from app.settings import settings

router = APIRouter()


@router.post("/command")
@handle_exceptions
async def command_handler(request: Request, bot: Bot = bot_dependency) -> JSONResponse:
"""Receive commands from users. Max timeout - 5 seconds."""
try: # noqa: WPS225
bot.async_execute_raw_bot_command(
await request.json(),
request_headers=request.headers,
)
except ValueError:
error_label = "Bot command validation error"

if settings.DEBUG:
logger.exception(error_label)
else:
logger.warning(error_label)

return JSONResponse(
build_bot_disabled_response(error_label),
status_code=HTTPStatus.SERVICE_UNAVAILABLE,
)
except UnknownBotAccountError as exc:
error_label = f"No credentials for bot {exc.bot_id}"
logger.warning(error_label)

return JSONResponse(
build_bot_disabled_response(error_label),
status_code=HTTPStatus.SERVICE_UNAVAILABLE,
)
except UnsupportedBotAPIVersionError as exc:
error_label = (
f"Unsupported Bot API version: `{exc.version}`. "
f"Set protocol version to `{BOT_API_VERSION}` in Admin panel."
)
logger.warning(error_label)

return JSONResponse(
build_bot_disabled_response(error_label),
status_code=HTTPStatus.SERVICE_UNAVAILABLE,
)
except UnverifiedRequestError as exc:
logger.warning(f"UnverifiedRequestError: {exc.args[0]}")
return JSONResponse(
content=build_unverified_request_response(
status_message=exc.args[0],
),
status_code=HTTPStatus.UNAUTHORIZED,
)

bot.async_execute_raw_bot_command(
await request.json(),
request_headers=request.headers,
)
return JSONResponse(
build_command_accepted_response(), status_code=HTTPStatus.ACCEPTED
)


@router.post("/smartapps/request")
@handle_exceptions
async def sync_smartapp_event_handler(
request: Request, bot: Bot = bot_dependency
) -> JSONResponse:
response = await bot.sync_execute_raw_smartapp_event(
await request.json(),
request_headers=request.headers,
)
return JSONResponse(response.jsonable_dict(), status_code=HTTPStatus.OK)


@router.get("/status")
async def status_handler(request: Request, bot: Bot = bot_dependency) -> JSONResponse:
"""Show bot status and commands list."""
Expand Down
Empty file.
66 changes: 66 additions & 0 deletions backend/app/api/exceptions/botx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""Handlers for BotX request exceptions."""

from functools import wraps
from http import HTTPStatus
from typing import Any, Callable

from fastapi.responses import JSONResponse
from pybotx import (
UnknownBotAccountError,
UnsupportedBotAPIVersionError,
UnverifiedRequestError,
build_bot_disabled_response,
build_unverified_request_response,
)
from pybotx.constants import BOT_API_VERSION

from app.logger import logger
from app.settings import settings


def handle_exceptions(func: Callable) -> Callable: # noqa: WPS212
@wraps(func)
async def wrapper(*args: Any, **kwargs: Any) -> JSONResponse:
try: # noqa: WPS225
return await func(*args, **kwargs)
except ValueError:
error_label = "Bot command validation error"

if settings.DEBUG:
logger.exception(error_label)
else:
logger.warning(error_label)

return JSONResponse(
build_bot_disabled_response(error_label),
status_code=HTTPStatus.SERVICE_UNAVAILABLE,
)
except UnknownBotAccountError as exc:
error_label = f"No credentials for bot {exc.bot_id}"
logger.warning(error_label)

return JSONResponse(
build_bot_disabled_response(error_label),
status_code=HTTPStatus.SERVICE_UNAVAILABLE,
)
except UnsupportedBotAPIVersionError as exc:
error_label = (
f"Unsupported Bot API version: `{exc.version}`. "
f"Set protocol version to `{BOT_API_VERSION}` in Admin panel."
)
logger.warning(error_label)

return JSONResponse(
build_bot_disabled_response(error_label),
status_code=HTTPStatus.SERVICE_UNAVAILABLE,
)
except UnverifiedRequestError as exc:
logger.warning(f"UnverifiedRequestError: {exc.args[0]}")
return JSONResponse(
content=build_unverified_request_response(
status_message=exc.args[0],
),
status_code=HTTPStatus.UNAUTHORIZED,
)

return wrapper
9 changes: 9 additions & 0 deletions backend/app/bot/commands/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
IncomingMessage,
SmartAppEvent,
StatusRecipient,
SyncSmartAppEventResponsePayload,
)

from app.bot.smartapp import smartapp
from app.resources import strings

collector = HandlerCollector()
Expand Down Expand Up @@ -49,6 +51,13 @@ async def help_handler(message: IncomingMessage, bot: Bot) -> None:
await bot.answer_message(answer_body)


@collector.sync_smartapp_event
async def handle_sync_smartapp_event(
event: SmartAppEvent, bot: Bot
) -> SyncSmartAppEventResponsePayload:
return await smartapp.handle_sync_smartapp_event(event, bot)


@collector.command("/_debug:git-commit-sha", visible=False)
async def git_commit_sha(message: IncomingMessage, bot: Bot) -> None:
"""Show git commit SHA."""
Expand Down
Loading
Loading