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
|
.env
|
||||||
.vscode/
|
.vscode/
|
||||||
.venv/
|
.venv/
|
||||||
.log
|
.log/
|
||||||
|
*.log
|
||||||
.idea/
|
.idea/
|
||||||
*.idea
|
*.idea
|
||||||
|
docker/local_redis_file/data
|
81
README.md
81
README.md
|
@ -1,2 +1,83 @@
|
||||||
# osnova-api-alert
|
# 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