commit
8464ae53a5
|
@ -0,0 +1,22 @@
|
|||
name: Docker Build
|
||||
on:
|
||||
merge:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
build:
|
||||
runs-on: runner-app01-osnova-api-alert
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: build
|
||||
run: |
|
||||
docker login git.sm8255082.ru --username sergey --password ${{ secrets.GSP }}
|
||||
docker build -t osnova-api-alert:latest -f .docker/Dockerfile .
|
||||
- name: push latest
|
||||
run: |
|
||||
docker tag home-tg-bot:latest git.sm8255082.ru/sergey/osnova-api-alert:latest
|
||||
docker push git.sm8255082.ru/sergey/osnova-api-alert:latest
|
||||
- name: push curent version
|
||||
run: |
|
||||
docker tag home-tg-bot:latest git.sm8255082.ru/Osnova/osnova-api-alert:0.0.1
|
||||
docker push git.sm8255082.ru/sergey/osnova-api-alert:0.0.1
|
|
@ -3,6 +3,8 @@ __pycache__
|
|||
.env
|
||||
.vscode/
|
||||
.venv/
|
||||
.log
|
||||
.log/
|
||||
*.log
|
||||
.idea/
|
||||
*.idea
|
||||
docker/local_redis_file/data
|
81
README.md
81
README.md
|
@ -1,2 +1,83 @@
|
|||
# osnova-api-alert
|
||||
|
||||
swagger - https://osnova-api-alert.sm8255082.ru/docs
|
||||
|
||||
endpoints:
|
||||
- https://osnova-api-alert.sm8255082.ru/ping (get, post)
|
||||
без авторизации, без параметров
|
||||
- https://osnova-api-alert.sm8255082.ru/api/v1/zbx/send-to-dashboard (post)
|
||||
в заголовке должен быть токен 'x-api-key: токен'
|
||||
должны предаваться в data:
|
||||
|
||||
```json
|
||||
{
|
||||
"text": "string",
|
||||
"subject": "string",
|
||||
"problem_id": 0
|
||||
}
|
||||
```
|
||||
- https://osnova-api-alert.sm8255082.ru/api/v1/zbx/send-to-net-chat (post)
|
||||
в заголовке должен быть токен 'x-api-key: токен'
|
||||
должны предаваться в data:
|
||||
|
||||
```json
|
||||
{
|
||||
"text": "string",
|
||||
"subject": "string"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
js для заббикса:
|
||||
|
||||
```javascript
|
||||
function sendMessage(value) {
|
||||
var params = JSON.parse(value),
|
||||
data,
|
||||
response,
|
||||
request = new HttpRequest(),
|
||||
url = 'https://osnova-api-alert.sm8255082.ru/api/v1/tg/send';
|
||||
request.addHeader('Content-Type: application/json');
|
||||
request.addHeader('x-api-key: токен');
|
||||
data = JSON.stringify(params);
|
||||
response = request.post(url, data);
|
||||
|
||||
if (request.getStatus() === 200) {
|
||||
return 'OK';
|
||||
}
|
||||
else {
|
||||
if (typeof response.description === 'string') {
|
||||
throw response.description;
|
||||
}
|
||||
else {
|
||||
throw 'Unknown error. Check debug log for more information.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
Zabbix.log(4, value)
|
||||
sendMessage(value);
|
||||
return 'OK';
|
||||
}
|
||||
catch (error) {
|
||||
throw 'Unknown error ' + error;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
You can try to get the message_thread_id from the message link
|
||||
|
||||
- send a message to the topic you need from the application
|
||||
- right click on the sent message and choose "Copy message link"
|
||||
- paste link somewhere
|
||||
- you will see something like this: https://t.me/c/1112223334/25/33
|
||||
- the value 25(value after long number) from the link will be message_thread_id
|
||||
|
||||
I assume that -100 + 1112223334 - will be equal chat_id
|
||||
|
||||
The number after will be message_thread_id
|
||||
|
||||
And the last one should be message_id
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
from .static_env import verify_user_pwd, verify_token_zabbix
|
||||
|
||||
__all__ = [
|
||||
"verify_user_pwd",
|
||||
"verify_token_zabbix",
|
||||
]
|
|
@ -0,0 +1,31 @@
|
|||
from fastapi import Depends, HTTPException, status
|
||||
from fastapi.security import APIKeyHeader
|
||||
from fastapi.security import HTTPBasic, HTTPBasicCredentials
|
||||
from config import conf
|
||||
import logging as log
|
||||
|
||||
security = HTTPBasic()
|
||||
api_key_header = APIKeyHeader(name="X-API-KEY", auto_error=False)
|
||||
|
||||
|
||||
def verify_token_zabbix(token: str = Depends(api_key_header)):
|
||||
if token != conf.zbx.token:
|
||||
log.warning("Invalid token")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Invalid authentication credentials",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
|
||||
|
||||
def verify_user_pwd(credentials: HTTPBasicCredentials = Depends(security)):
|
||||
if (
|
||||
credentials.username != conf.swagger.login
|
||||
or credentials.password != conf.swagger.pwd
|
||||
):
|
||||
log.warning("Invalid credentials")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Invalid credentials",
|
||||
headers={"WWW-Authenticate": "Basic"},
|
||||
)
|
|
@ -0,0 +1,21 @@
|
|||
OAA_CFG__RUN__HOST=0.0.0.0
|
||||
OAA_CFG__RUN__PORT=8000
|
||||
OAA_CFG__RUN__RELOAD=True
|
||||
|
||||
OAA_CFG__LOG__LEVEL=30
|
||||
OAA_CFG__LOG__LEVEL_TO_FILE=30
|
||||
|
||||
OAA_CFG__SWAGGER__LOGIN=admin
|
||||
OAA_CFG__SWAGGER__PWD=P@ssw0rd!
|
||||
|
||||
OAA_CFG__REDIS__HOST=localhost
|
||||
OAA_CFG__REDIS__PORT=6379
|
||||
OAA_CFG__REDIS__PWD=P@ssw0rd!
|
||||
|
||||
OAA_CFG__TG__BOT_TOKEN=string
|
||||
OAA_CFG__TG__CHAT_ID=0
|
||||
OAA_CFG__TG__DASHBOARD_TRED_ID=0
|
||||
OAA_CFG__TG__NET_TRED_ID=0
|
||||
|
||||
OAA_CFG__ZBX__TOKEN=string
|
||||
OAA_CFG__ZBX__CLOSE_ALERT_PATTERN=^Problem has been resolved
|
|
@ -0,0 +1,7 @@
|
|||
from .config import conf, STATIC_DIR
|
||||
|
||||
|
||||
__all__ = [
|
||||
"conf",
|
||||
STATIC_DIR,
|
||||
]
|
|
@ -0,0 +1,104 @@
|
|||
from pydantic import BaseModel
|
||||
from pydantic_settings import (
|
||||
BaseSettings,
|
||||
SettingsConfigDict,
|
||||
)
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
BASE_DIR = Path(__file__).parent.parent
|
||||
TEMPLATES_DIR = BASE_DIR / "web" / "templates"
|
||||
STATIC_DIR = BASE_DIR / "web" / "static"
|
||||
|
||||
|
||||
class RunConfig(BaseModel):
|
||||
host: str = "0.0.0.0"
|
||||
port: int = 8000
|
||||
reload: bool = False
|
||||
|
||||
|
||||
class LogConfig(BaseModel):
|
||||
level: int = 30
|
||||
level_to_file: int = 30
|
||||
dateformat: str = "%Y-%m-%d %H:%M:%S"
|
||||
format: str = (
|
||||
"[%(asctime)s.%(msecs)03d] %(module)-25s:%(lineno)4d | %(funcName)-20s| %(levelname)-8s | %(message)s"
|
||||
)
|
||||
|
||||
|
||||
class PrefixConfig(BaseModel):
|
||||
swagger: str = "/docs"
|
||||
api_v1: str = "/api/v1"
|
||||
tg_v1: str = api_v1 + "/tg"
|
||||
ping: str = "/ping"
|
||||
zbx: str = api_v1 + "/zbx"
|
||||
|
||||
|
||||
class RedisConfig(BaseModel):
|
||||
host: str = "localhost"
|
||||
port: int = 6379
|
||||
pwd: str | None = None
|
||||
|
||||
|
||||
class TelegramConfig(BaseModel):
|
||||
bot_token: str
|
||||
chat_id: int
|
||||
dashboard_tred_id: int | None = None
|
||||
net_tred_id: int | None = None
|
||||
|
||||
|
||||
class FromZabbix(BaseModel):
|
||||
token: str
|
||||
close_alert_pattern: str
|
||||
|
||||
|
||||
class SwaggerConfig(BaseModel):
|
||||
openapi_url: str = "/openapi.json"
|
||||
title: str = "API"
|
||||
oauth2_redirect_url: str = "/docs/oauth2-redirect"
|
||||
swagger_js_url: str = "/static/swagger/swagger-ui-bundle.js"
|
||||
swagger_css_url: str = "/static/swagger/swagger-ui.css"
|
||||
swagger_favicon_url: str = "/static/swagger/favicon.png"
|
||||
login: str
|
||||
pwd: str
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
model_config = SettingsConfigDict(
|
||||
env_file=(
|
||||
BASE_DIR / "config" / ".env-template",
|
||||
BASE_DIR / "config" / ".env",
|
||||
),
|
||||
case_sensitive=False,
|
||||
env_nested_delimiter="__",
|
||||
env_prefix="OAA_CFG__",
|
||||
)
|
||||
run: RunConfig = RunConfig()
|
||||
swagger: SwaggerConfig
|
||||
log: LogConfig = LogConfig()
|
||||
prefix: PrefixConfig = PrefixConfig()
|
||||
redis: RedisConfig
|
||||
tg: TelegramConfig
|
||||
zbx: FromZabbix
|
||||
|
||||
|
||||
conf = Settings()
|
||||
|
||||
|
||||
logging.basicConfig(
|
||||
level=conf.log.level,
|
||||
datefmt=conf.log.dateformat,
|
||||
format=conf.log.format,
|
||||
)
|
||||
|
||||
file_handler = logging.FileHandler(BASE_DIR / "logfile.log")
|
||||
file_handler.setLevel(conf.log.level_to_file)
|
||||
file_handler.setFormatter(
|
||||
logging.Formatter(
|
||||
"[%(asctime)s.%(msecs)03d] %(module)s:%(lineno)4d | %(funcName)s| %(levelname)s | %(message)s"
|
||||
)
|
||||
)
|
||||
logging.getLogger().addHandler(file_handler)
|
|
@ -0,0 +1,12 @@
|
|||
FROM python:3.12
|
||||
ADD auth ./auth
|
||||
ADD config ./config
|
||||
ADD redis_db ./redis_db
|
||||
ADD routers ./routers
|
||||
ADD schemas ./schemas
|
||||
ADD telegram ./telegram
|
||||
ADD web ./web
|
||||
ADD main.py ./main.py
|
||||
ADD requirements.txt /requirements.txt
|
||||
RUN pip install -r requirements.txt --root-user-action=ignore
|
||||
CMD ["python", "main.py"]
|
|
@ -0,0 +1,12 @@
|
|||
version: '3.3'
|
||||
|
||||
services:
|
||||
redis:
|
||||
image: redis:latest
|
||||
restart: always
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- ./local_redis_file/data:/data
|
||||
#command: ["redis-server", --port 6379]
|
||||
command: [redis-server, --protected-mode yes, --port 6379, --requirepass, P@ssw0rd!]
|
36
main.py
36
main.py
|
@ -0,0 +1,36 @@
|
|||
import logging as log
|
||||
from config import conf, STATIC_DIR
|
||||
import uvicorn
|
||||
from fastapi import FastAPI
|
||||
from fastapi.responses import ORJSONResponse
|
||||
from starlette.staticfiles import StaticFiles
|
||||
from routers import router
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
yield
|
||||
log.info("main APP stopped")
|
||||
|
||||
|
||||
main_app = FastAPI(
|
||||
default_response_class=ORJSONResponse,
|
||||
docs_url=None,
|
||||
lifespan=lifespan,
|
||||
)
|
||||
|
||||
main_app.include_router(router)
|
||||
|
||||
main_app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
log.info("Starting server")
|
||||
uvicorn.run(
|
||||
"main:main_app",
|
||||
host=conf.run.host,
|
||||
port=conf.run.port,
|
||||
reload=conf.run.reload,
|
||||
)
|
||||
log.info("Server stopped")
|
|
@ -0,0 +1,12 @@
|
|||
[Unit]
|
||||
Description=Send alert from Osnova to telegram
|
||||
After=multi-user.target
|
||||
|
||||
[Service]
|
||||
User=linuxadm
|
||||
Type=simple
|
||||
Restart=always
|
||||
ExecStart=/home/linuxadm/python-scripts/osnova-api-alert/.venv/bin/python3 /home/linuxadm/python-scripts/osnova-api-alert/main.py
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,24 @@
|
|||
[tool.poetry]
|
||||
name = "app-api-alert"
|
||||
version = "0.1.0"
|
||||
description = ""
|
||||
authors = ["sergey <sergey@sm8255082.ru>"]
|
||||
license = "GNU GENERAL PUBLIC LICENSE"
|
||||
readme = "README.md"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.12"
|
||||
pydantic-settings = "^2.5.2"
|
||||
fastapi = "^0.115.0"
|
||||
uvicorn = {extras = ["standard"], version = "^0.31.0"}
|
||||
orjson = "^3.10.7"
|
||||
redis = "^5.1.1"
|
||||
aiohttp = "^3.10.9"
|
||||
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
black = "^24.8.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
|
@ -0,0 +1,13 @@
|
|||
from .crud import (
|
||||
get_value,
|
||||
set_value,
|
||||
ping,
|
||||
pop_value,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"get_value",
|
||||
"set_value",
|
||||
"ping",
|
||||
"pop_value",
|
||||
]
|
|
@ -0,0 +1,33 @@
|
|||
import logging as log
|
||||
from .r_helper import RedisManager
|
||||
|
||||
|
||||
async def ping():
|
||||
async with RedisManager() as redis_connect:
|
||||
if redis_connect:
|
||||
result = await redis_connect.client.ping()
|
||||
log.info("Ping - %s", result)
|
||||
return result
|
||||
|
||||
|
||||
async def set_value(key, value):
|
||||
async with RedisManager() as redis_connect:
|
||||
if redis_connect:
|
||||
await redis_connect.client.set(key, value)
|
||||
log.info("Set %s = %s", key, value)
|
||||
|
||||
|
||||
async def get_value(key):
|
||||
async with RedisManager() as redis_connect:
|
||||
if redis_connect:
|
||||
value = await redis_connect.client.get(key)
|
||||
log.info("Get %s = %s", key, value)
|
||||
return value
|
||||
|
||||
|
||||
async def pop_value(key):
|
||||
async with RedisManager() as redis_connect:
|
||||
if redis_connect:
|
||||
value = await redis_connect.client.getdel(key)
|
||||
log.info("Get and delete %s = %s", key, value)
|
||||
return value
|
|
@ -0,0 +1,30 @@
|
|||
from redis.asyncio import Redis
|
||||
from redis import ConnectionError
|
||||
from config import conf
|
||||
import logging as log
|
||||
|
||||
|
||||
class RedisManager:
|
||||
def __init__(self):
|
||||
self.client = None
|
||||
self.connect_params = {
|
||||
"host": conf.redis.host,
|
||||
"port": conf.redis.port,
|
||||
}
|
||||
if conf.redis.pwd:
|
||||
self.connect_params["password"] = conf.redis.pwd
|
||||
|
||||
async def __aenter__(self):
|
||||
self.client = Redis(**self.connect_params)
|
||||
try:
|
||||
await self.client.ping()
|
||||
log.info("connected to Redis")
|
||||
return self
|
||||
except ConnectionError:
|
||||
log.warning("failed to connect to Redis")
|
||||
self.client = None
|
||||
|
||||
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
||||
if self.client:
|
||||
await self.client.close()
|
||||
log.info("closed connection to Redis")
|
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
|
@ -0,0 +1,25 @@
|
|||
from fastapi import APIRouter
|
||||
|
||||
from .swagger import router as swagger_router
|
||||
from .ping import router as ping_router
|
||||
from .from_zbx import router as zbx_router
|
||||
from config import conf
|
||||
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
router.include_router(
|
||||
swagger_router,
|
||||
prefix=conf.prefix.swagger,
|
||||
)
|
||||
router.include_router(
|
||||
ping_router,
|
||||
prefix=conf.prefix.ping,
|
||||
tags=["Ping"],
|
||||
)
|
||||
|
||||
router.include_router(
|
||||
zbx_router,
|
||||
prefix=conf.prefix.zbx,
|
||||
tags=["From Zabbix"],
|
||||
)
|
|
@ -0,0 +1,50 @@
|
|||
from fastapi import APIRouter, Depends
|
||||
import logging as log
|
||||
|
||||
from schemas import (
|
||||
zbxMessageToDashboard,
|
||||
zbxMessageToNetworkChat,
|
||||
)
|
||||
from auth import verify_token_zabbix
|
||||
from redis_db import set_value, pop_value
|
||||
from config import conf
|
||||
import re
|
||||
from telegram import send_message
|
||||
from telegram import del_message
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post("/send-to-dashboard")
|
||||
async def send_message_to_dashboard(
|
||||
message: zbxMessageToDashboard,
|
||||
token: str = Depends(verify_token_zabbix),
|
||||
):
|
||||
match = re.search(conf.zbx.close_alert_pattern, message.text)
|
||||
log.info(f"match: {match}")
|
||||
if match:
|
||||
msg_id = await pop_value(message.problem_id)
|
||||
if msg_id:
|
||||
msg_id = int(msg_id.decode("utf-8"))
|
||||
await del_message(message_id=msg_id, chat_id=conf.tg.chat_id)
|
||||
return
|
||||
|
||||
result = await send_message(
|
||||
text=message.subject + "\n\n" + message.text,
|
||||
chat_id=conf.tg.chat_id,
|
||||
message_thread_id=conf.tg.dashboard_tred_id,
|
||||
)
|
||||
if result and result["status"] == 200:
|
||||
await set_value(message.problem_id, result["msg_id"])
|
||||
|
||||
|
||||
@router.post("/send-to-net-chat")
|
||||
async def send_message_to_net_chat(
|
||||
message: zbxMessageToNetworkChat,
|
||||
token: str = Depends(verify_token_zabbix),
|
||||
):
|
||||
await send_message(
|
||||
text=message.subject + "\n\n" + message.text,
|
||||
chat_id=conf.tg.chat_id,
|
||||
message_thread_id=conf.tg.net_tred_id,
|
||||
)
|
|
@ -0,0 +1,16 @@
|
|||
from fastapi import APIRouter
|
||||
from redis_db import ping
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("")
|
||||
async def ping_post():
|
||||
redis_ping = await ping()
|
||||
return {"ok": True, "redis": redis_ping}
|
||||
|
||||
|
||||
@router.post("")
|
||||
async def ping_get():
|
||||
redis_ping = await ping()
|
||||
return {"ok": True, "redis": redis_ping}
|
|
@ -0,0 +1,29 @@
|
|||
from fastapi import APIRouter, Depends
|
||||
|
||||
from fastapi.openapi.docs import get_swagger_ui_html
|
||||
from fastapi.security import HTTPBasicCredentials
|
||||
|
||||
from config import conf
|
||||
|
||||
from auth import verify_user_pwd
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from fastapi.security import HTTPBasicCredentials
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("", include_in_schema=False)
|
||||
async def custom_swagger_ui_html(
|
||||
credentials: HTTPBasicCredentials = Depends(verify_user_pwd),
|
||||
):
|
||||
return get_swagger_ui_html(
|
||||
openapi_url=conf.swagger.openapi_url,
|
||||
title=conf.swagger.title,
|
||||
oauth2_redirect_url=conf.swagger.oauth2_redirect_url,
|
||||
swagger_js_url=conf.swagger.swagger_js_url,
|
||||
swagger_css_url=conf.swagger.swagger_css_url,
|
||||
swagger_favicon_url=conf.swagger.swagger_favicon_url,
|
||||
)
|
|
@ -0,0 +1,9 @@
|
|||
from .from_zabbix import (
|
||||
MessageToDashboard as zbxMessageToDashboard,
|
||||
MessageToNetworkChat as zbxMessageToNetworkChat,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"zbxMessageToDashboard",
|
||||
"zbxMessageToNetworkChat",
|
||||
]
|
|
@ -0,0 +1,14 @@
|
|||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Message(BaseModel):
|
||||
text: str
|
||||
|
||||
|
||||
class MessageToDashboard(Message):
|
||||
subject: str
|
||||
problem_id: int
|
||||
|
||||
|
||||
class MessageToNetworkChat(Message):
|
||||
subject: str
|
|
@ -0,0 +1,9 @@
|
|||
from .message import (
|
||||
send_message,
|
||||
del_message,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"send_message",
|
||||
"del_message",
|
||||
]
|
|
@ -0,0 +1,53 @@
|
|||
import logging as log
|
||||
|
||||
import aiohttp
|
||||
from config import conf
|
||||
|
||||
|
||||
async def send_message(
|
||||
text: str,
|
||||
chat_id: int,
|
||||
message_thread_id: int | None = None,
|
||||
) -> dict | None:
|
||||
url = f"https://api.telegram.org/bot{conf.tg.bot_token}/sendMessage"
|
||||
params = {
|
||||
"chat_id": chat_id,
|
||||
"text": text,
|
||||
}
|
||||
if message_thread_id:
|
||||
params["message_thread_id"] = message_thread_id
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.post(
|
||||
url,
|
||||
json=params,
|
||||
) as response:
|
||||
log.info(f"Response status: {response.status}")
|
||||
resp = await response.json()
|
||||
if response.status == 200:
|
||||
log.info(f"Message with ID: {resp['result']['message_id']} send")
|
||||
return {
|
||||
"status": response.status,
|
||||
"msg_id": resp["result"]["message_id"],
|
||||
}
|
||||
log.warning(f"Message not send. Response status: {response.status}")
|
||||
|
||||
|
||||
async def del_message(
|
||||
message_id: int,
|
||||
chat_id: int,
|
||||
) -> dict | None:
|
||||
url = f"https://api.telegram.org/bot{conf.tg.bot_token}/deleteMessage"
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.post(
|
||||
url,
|
||||
json={
|
||||
"chat_id": chat_id,
|
||||
"message_id": message_id,
|
||||
},
|
||||
) as response:
|
||||
if response.status == 200:
|
||||
log.info(f"Message ID {message_id} deleted")
|
||||
return {
|
||||
"status": response.status,
|
||||
}
|
||||
log.warning(f"Response status: {response.status}")
|
Binary file not shown.
After Width: | Height: | Size: 4.9 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue