Skip to content

Commit

Permalink
Merge pull request #22 from p2p-org/PK-1651-alert-subscriptions
Browse files Browse the repository at this point in the history
PK-1651 alert subscriptions
  • Loading branch information
SergeyRadchenkoP2P authored Nov 21, 2023
2 parents 1b468bf + 4505e22 commit afcefaa
Show file tree
Hide file tree
Showing 25 changed files with 807 additions and 308 deletions.
6 changes: 3 additions & 3 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
"version": "0.2.0",
"configurations": [
{
"name": "bot",
"name": "Bot",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/bot/app/__main__.py",
"cwd": "${workspaceFolder}/bot/app/",
"console": "integratedTerminal",
"envFile": "${workspaceFolder}/bot.env",
"justMyCode": true
"justMyCode": true,
"envFile": "${workspaceFolder}/bot.env"
}
]
}
5 changes: 4 additions & 1 deletion bot.env
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
tg_token=""
admin_chat=""
db_name="adm"
prometheus_rules_url="http://localhost:9090/api/v1/rules"
prometheus_alert_groups="maas-rules"
db_name="maas"
db_user="adm"
db_pass="adm"
db_port="5432"
23 changes: 14 additions & 9 deletions bot/app/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
from message_handlers.setup import setup_message_handler
from web_apps.setup import setup_web_app
from forms.setup import setup_message_form
from callback_data.main import Cb
from callback_data.main import CbData
from aiohttp import web
from utils.db import DB
import time
from utils import subscriptions

logging.basicConfig(level=logging.INFO, stream=sys.stdout)

Expand All @@ -24,29 +24,34 @@
db_host = os.environ['db_host']
db_port = os.environ['db_port']

run_mode = os.environ.get('run_mode', 'standalone')
grafana_url = os.environ.get('grafana_url', 'http://127.0.0.1:3000/d/fDrj0_EGz/p2p-org-polkadot-kusama-dashboard?orgId=1')
prometheus_rules_url = os.environ.get('prometheus_rules_url', 'http://localhost:9090/api/v1/rules')
prometheus_alert_groups = os.environ.get('prometheus_alert_groups', [])
if isinstance(prometheus_alert_groups, str):
prometheus_alert_groups = prometheus_alert_groups.split(',')

web_app = web.Application()
db = DB(db_name,db_user,db_pass,db_host,db_port)

subs = subscriptions.Subscriptions(db, prometheus_rules_url, prometheus_alert_groups)
bot = Bot(token=tg_token, parse_mode="HTML")

storage = MemoryStorage()
dp = Dispatcher(storage=storage)

router = Router()
dp.include_router(router)

cb = Cb
cb = CbData

setup_message_handler('start')
# setup_message_handler('support')

# setup_message_form('support')
setup_message_form('sub_filter')
setup_message_form('support')

setup_web_app('ping')
setup_web_app('prom_alert')

from callback_query_handlers import promalert,main_menu,grafana,support
from callback_query_handlers import promalert,main_menu,support,subscriptions

web_runner = web.AppRunner(web_app)
loop = asyncio.get_event_loop()
Expand Down
2 changes: 1 addition & 1 deletion bot/app/callback_data/main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from aiogram.filters.callback_data import CallbackData

class Cb(CallbackData, prefix="main"):
class CbData(CallbackData, prefix="main"):
dst: str
data: str
69 changes: 0 additions & 69 deletions bot/app/callback_query_handlers/grafana.py

This file was deleted.

24 changes: 12 additions & 12 deletions bot/app/callback_query_handlers/main_menu.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
from __main__ import router,dp,db,bot,cb
from aiogram.types import CallbackQuery,InlineKeyboardButton,InlineKeyboardMarkup
from callback_data.main import CbData
from __main__ import router
from aiogram.types import CallbackQuery
from utils.menu_builder import MenuBuilder
from aiogram import F

@router.callback_query(cb.filter(F.dst == 'main_menu'))
async def menu_prom_cb_handler(query: CallbackQuery,callback_data: cb):
chat_id = query.message.chat.id
message_id = query.message.message_id
def main_menu():
return 'Please select', MenuBuilder().build(preset='main_menu')

menu = MenuBuilder()
menu = menu.build(callback_data=cb,preset='main_menu')

await bot.send_message(chat_id,"Here is a main menu.",reply_markup=menu.as_markup())
await bot.delete_message(chat_id,message_id)
await query.answer(query.id)
@router.callback_query(CbData.filter(F.dst == 'main_menu'))
async def menu_prom_cb_handler(query: CallbackQuery):

text, keyboard = main_menu()

call = query.message.edit_text(text=text, reply_markup=keyboard.as_markup())
await query.bot(call)
await query.answer('main menu')
60 changes: 48 additions & 12 deletions bot/app/callback_query_handlers/promalert.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,55 @@
from __main__ import router,dp,db,bot,cb
from aiogram.types import CallbackQuery,InlineKeyboardButton,InlineKeyboardMarkup
from callback_data.main import CbData
from __main__ import router, db, subs
from aiogram.types import CallbackQuery
from aiogram.utils.keyboard import InlineKeyboardBuilder
from aiogram import F
from utils.menu_builder import MenuBuilder
from utils.db import DB
from utils.subscriptions import Subscriptions
from aiogram.fsm.context import FSMContext

assert isinstance(db, DB)
assert isinstance(subs, Subscriptions)

@router.callback_query(cb.filter(F.dst == 'promalert'))
async def menu_prom_cb_handler(query: CallbackQuery,callback_data: cb):
await query.answer(query.id)

username = query.message.chat.username
chat_id = query.message.chat.id
message_id = query.message.message_id
def promalert_dialog(promalert_status: str = '', chat_id: int = 0) -> (str, InlineKeyboardBuilder):
s = subs.get_subscriptions(chat_id)
if promalert_status == '':
promalert_status = db.get_records('promalert_status', 'id', chat_id)
text = []
if promalert_status != 'on':
promalert_status = 'off'
text.append(f'Notifications: {promalert_status}')
text.append(f'Subscriptions count: {len(s)}')

menu = MenuBuilder()
menu = menu.build(callback_data=cb,preset='promalert',button_back='main_menu')
if promalert_status == 'off':
menu.add(preset='promalert_on')
else:
menu.add(preset='promalert_off')
menu.add(preset='sub_rules')
if len(s) > 0:
menu.add(preset='sub_list')
return '\n'.join(text), menu.build(button_back='main_menu')

await bot.send_message(chat_id,"You can subscribe or deactivate subsription hete.",reply_markup=menu.as_markup())
await bot.delete_message(chat_id,message_id)
@router.callback_query(CbData.filter(F.dst == 'promalert'))
async def handle_promalert(query: CallbackQuery):
text, keyboard = promalert_dialog(chat_id=query.message.chat.id)
call = query.message.edit_text(text=text, reply_markup=keyboard.as_markup())
await query.bot(call)
await query.answer('alerts menu')

@router.callback_query(CbData.filter(F.dst == 'promalert_on'))
async def handle_promalert_on(query: CallbackQuery):
db.update_record(query.message.chat.id, 'promalert_status', 'on')
text, keyboard = promalert_dialog(chat_id=query.message.chat.id, promalert_status='on')
call = query.message.edit_text(text=text, reply_markup=keyboard.as_markup())
await query.bot(call)
await query.answer('notifications enabled')

@router.callback_query(CbData.filter(F.dst == 'promalert_off'))
async def handle_promalert_off(query: CallbackQuery):
db.update_record(query.message.chat.id, 'promalert_status', 'off')
text, keyboard = promalert_dialog(chat_id=query.message.chat.id, promalert_status='off')
call = query.message.edit_text(text=text, reply_markup=keyboard.as_markup())
await query.bot(call)
await query.answer('notifications disabled')
112 changes: 112 additions & 0 deletions bot/app/callback_query_handlers/subscriptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
from aiogram.types import CallbackQuery
from callback_data.main import CbData
from __main__ import router, subs
from utils.subscriptions import Subscriptions
from utils.menu_builder import MenuBuilder
from utils.msg_text import dict2text, text2dict
from aiogram.fsm.context import FSMContext
from aiogram import F
from forms.sub_filter import Form, sub_filter_input_validate
from callback_query_handlers.promalert import promalert_dialog
assert isinstance(subs, Subscriptions)

# Show rules list after Add subscription click
@router.callback_query(CbData.filter(F.dst == 'sub_rules'))
async def handle_sub_rules(query: CallbackQuery, callback_data: CbData):
r = await subs.get_rules()
rules = r.list()
keyboard = MenuBuilder().add(preset='rules_list', data=rules, navigation=callback_data.data)
call = query.message.edit_text(text='Please select alert you would like to subscribe to.',
reply_markup=keyboard.build().as_markup())
await query.bot(call)
await query.answer('Ok')

# Show single rule for subscription and edit buttons
@router.callback_query(CbData.filter(F.dst == 'sub_rule'))
async def handle_sub_rule(query: CallbackQuery, callback_data: CbData):
r = await subs.get_rule_by_name(callback_data.data)
rule = r.dict()
keyboard = MenuBuilder()
keyboard.add(preset='sub_filter_edit', data=rule)
keyboard.add(preset='sub_save', data=r.alertname)
text = 'Use buttons to configure subscription "Edit ..." to specify filters, Save to subscribe or Back to cancel\n'
call = query.message.edit_text(text=text+dict2text(rule), reply_markup=keyboard.build(button_back='promalert').as_markup())
await query.bot(call)
await query.answer('Ok')

# Show existing subscriptions
@router.callback_query(CbData.filter(F.dst == 'sub_list'))
async def handle_sub_list(query: CallbackQuery, callback_data: CbData):
if callback_data.data == '':
new_page = 0
else:
new_page = int(callback_data.data.split('/')[0])
s, total = subs.get_subscription_by_index(query.from_user.id, new_page)

keyboard = MenuBuilder()
keyboard.add(preset='sub_filter_edit', data=s.keys())
keyboard.add(preset='sub_del', data=s['alertname'][0])
keyboard.add(preset='sub_scroll', navigation=f'{new_page}/{total}')
call = query.message.edit_text(text=dict2text(s), reply_markup=keyboard.build().as_markup())
await query.bot(call)
await query.answer('Ok')

# Turn on form.sub_filter and wait for field value
@router.callback_query(CbData.filter(F.dst == 'sub_edit'))
async def handle_sub_edit(query: CallbackQuery, callback_data: CbData, state: FSMContext):
d = text2dict(query.message.text)
await state.set_data({'expect': callback_data.data, 'current': d, 'message_id': query.message.message_id})
await state.set_state(Form.sub_filter)
text = f'Please send list of values for field <b>{callback_data.data}</b>\n'
keyboard = MenuBuilder()
call = query.message.edit_text(text=text, reply_markup=keyboard.build(button_back='sub_edit_cancel').as_markup())
await query.bot(call)
await query.answer(f'Please send values for: {callback_data.data}')

# Cancel form.sub_filter go promalert
@router.callback_query(CbData.filter(F.dst == 'sub_edit_cancel'))
async def handle_sub_edit(query: CallbackQuery, state: FSMContext):
await state.clear()
text, keyboard = promalert_dialog(chat_id=query.from_user.id)
call = query.message.edit_text(text=text, reply_markup=keyboard.as_markup())
await query.bot(call)
await query.answer('Canceled')

# Save alert from text message to database
@router.callback_query(CbData.filter(F.dst == 'sub_save'))
async def handle_sub_save(query: CallbackQuery, callback_data: CbData, state: FSMContext):
await state.clear()
if callback_data.data == '':
await query.answer('Something went wrong. Please try later.')
sub = text2dict(query.message.text)
for key, val in sub.items():
valid, reason = sub_filter_input_validate(expected=key, got=val)
if not valid:
keyboard = MenuBuilder()
keyboard.add(preset='sub_filter_edit', data=sub)
keyboard.add(preset='sub_save', data=sub['alertname'][0])
text = f'Unable to subscribe: <b>{reason}</b>. Please edit {key} field.\n'
await query.bot.send_message(text=text+dict2text(sub), chat_id=query.from_user.id,
reply_markup=keyboard.build(button_back='promalert').as_markup())
await query.answer(f'Please update {key}')
return
n = subs.user_subscribe(chat_id=query.from_user.id, subscription_name=callback_data.data, lvs=sub)
if n == 0:
await query.answer('Something went wrong. Please try later.')
text, keyboard = promalert_dialog(chat_id=query.from_user.id)
call = query.message.edit_text(text=text, reply_markup=keyboard.as_markup())
await query.bot(call)
await query.answer('Saved')

# Delete subscription
@router.callback_query(CbData.filter(F.dst == 'sub_del'))
async def handle_sub_del(query: CallbackQuery, callback_data: CbData, state: FSMContext):
await state.clear()
if callback_data.data == '':
await query.answer('Something went wrong. Please try later.')
subs.user_unsubscribe(chat_id=query.from_user.id, subscription_name=callback_data.data)
text, keyboard = promalert_dialog(chat_id=query.from_user.id)
call = query.message.edit_text(text=text, reply_markup=keyboard.as_markup())
await query.bot(call)
await query.answer('Deleted')

Loading

0 comments on commit afcefaa

Please sign in to comment.