0.0.7 fixes and graph
This commit is contained in:
parent
cbe9db4932
commit
297445fd50
|
@ -1,3 +1,9 @@
|
|||
## [0.0.7]
|
||||
|
||||
- исправления
|
||||
- команда, генерирующая граф связей
|
||||
|
||||
|
||||
## [0.0.6]
|
||||
|
||||
- совместимость с механизмом заявок для публичных групп
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from tgbot.config import WEBHOOK, FEEDBACK_CHAT_ID # init storage there
|
||||
from tgbot.handlers import handle_feedback, handle_answer, \
|
||||
handle_join, handle_left, handle_button, handle_join_request
|
||||
handle_join, handle_left, handle_button, handle_join_request, \
|
||||
handle_graph
|
||||
from tgbot.api import register_webhook
|
||||
from sanic import Sanic
|
||||
from sanic.response import text
|
||||
|
@ -31,9 +32,11 @@ async def handle(req):
|
|||
msg = update.get('message', update.get('edited_message'))
|
||||
if msg['chat']['type'] == 'private':
|
||||
handle_feedback(msg)
|
||||
elif str(msg['chat']['id']) == FEEDBACK_CHAT_ID \
|
||||
and 'reply_to_message' in msg:
|
||||
elif str(msg['chat']['id']) == FEEDBACK_CHAT_ID:
|
||||
if 'reply_to_message' in msg:
|
||||
handle_answer(msg)
|
||||
elif 'text' in msg and msg['text'] == '/graph':
|
||||
handle_graph(msg)
|
||||
else:
|
||||
if 'new_chat_member' in msg:
|
||||
handle_join(msg)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
sanic==19.6.0
|
||||
requests
|
||||
redis
|
||||
redis
|
||||
cairosvg
|
11
tgbot/api.py
11
tgbot/api.py
|
@ -85,4 +85,13 @@ def approve_chat_join_request(chat_id, user_id):
|
|||
url = apiBase + f"approveChatJoinRequest?chat_id={chat_id}" + \
|
||||
f'&user_id={user_id}'
|
||||
r = requests.post(url)
|
||||
return r
|
||||
return r
|
||||
|
||||
|
||||
def send_graph(png_data, chat_id):
|
||||
url = apiBase + f"sendPhoto"
|
||||
headers = {"Content-Type": "multipart/form-data"}
|
||||
files = {"photo": ("chart.png", png_data)}
|
||||
params = {"chat_id": chat_id}
|
||||
response = requests.post(url, headers=headers, files=files, params=params)
|
||||
return response.json()
|
|
@ -3,6 +3,6 @@ import os
|
|||
|
||||
WEBHOOK = os.environ.get('VERCEL_URL') or 'http://localhost:8000'
|
||||
REDIS_URL = os.environ.get('REDIS_URL') or 'redis://localhost:6379'
|
||||
NEWCOMER_MSG = os.environ.get('WELCOME_MSG') or "There is a newcomer, press the button if you are connected"
|
||||
NEWCOMER_MSG = os.environ.get('NEWCOMER_MSG') or "There is a newcomer, press the button if you are connected"
|
||||
BUTTON_VOUCH = os.environ.get('BUTTON_VOUCH') or 'My connection!'
|
||||
FEEDBACK_CHAT_ID = os.environ.get('FEEDBACK_CHAT_ID').replace("-", "-100")
|
64
tgbot/graph.py
Normal file
64
tgbot/graph.py
Normal file
|
@ -0,0 +1,64 @@
|
|||
import cairosvg
|
||||
|
||||
def generate_chart(members):
|
||||
# Размеры прямоугольника узла
|
||||
node_width = 150
|
||||
node_height = 50
|
||||
|
||||
# Размеры холста
|
||||
canvas_width = 800
|
||||
canvas_height = 600
|
||||
|
||||
# Радиус узла (для закругленных прямоугольников)
|
||||
node_radius = 10
|
||||
|
||||
# Цвета
|
||||
background_color = "#F2F2F2"
|
||||
node_color = "#EFEFEF"
|
||||
node_stroke_color = "#999"
|
||||
node_text_color = "#333"
|
||||
line_color = "#CCC"
|
||||
|
||||
# Список строк SVG-кода
|
||||
svg_lines = []
|
||||
|
||||
# Рассчитываем координаты для каждого узла
|
||||
coordinates = {}
|
||||
for member in members:
|
||||
x = member['x']
|
||||
y = member['y']
|
||||
coordinates[member['id']] = {'x': x, 'y': y}
|
||||
|
||||
# Рисуем линии-связи между узлами
|
||||
for member in members:
|
||||
member_id = member['id']
|
||||
x1 = coordinates[member_id]['x'] * node_width + node_width / 2
|
||||
y1 = coordinates[member_id]['y'] * node_height + node_height / 2
|
||||
for parent_id in member['parents']:
|
||||
x2 = coordinates[parent_id]['x'] * node_width + node_width / 2
|
||||
y2 = coordinates[parent_id]['y'] * node_height + node_height / 2
|
||||
svg_lines.append(f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" stroke="{line_color}" stroke-width="2"/>')
|
||||
|
||||
# Рисуем узлы
|
||||
for member in members:
|
||||
member_id = member['id']
|
||||
x = coordinates[member_id]['x'] * node_width
|
||||
y = coordinates[member_id]['y'] * node_height
|
||||
|
||||
# Рисуем фоновый прямоугольник
|
||||
svg_lines.append(f'<rect x="{x}" y="{y}" width="{node_width}" height="{node_height}" rx="{node_radius}" fill="{node_color}" stroke="{node_stroke_color}" stroke-width="2"/>')
|
||||
|
||||
# Добавляем текст в центр узла
|
||||
member_name = member['name'][:16]
|
||||
text_x = x + node_width / 2
|
||||
text_y = y + node_height / 2
|
||||
svg_lines.append(f'<text x="{text_x}" y="{text_y}" text-anchor="middle" dominant-baseline="central" font-size="16" fill="{node_text_color}">{member_name}</text>')
|
||||
|
||||
# Создаем SVG-код
|
||||
svg = f'<svg viewBox="0 0 {canvas_width} {canvas_height}" xmlns="http://www.w3.org/2000/svg" style="background-color:{background_color};">'
|
||||
for line in svg_lines:
|
||||
svg += line
|
||||
svg += '</svg>'
|
||||
# конвертировать SVG в PNG
|
||||
png_data = cairosvg.svg2png(bytestring=svg_data)
|
||||
return png_data
|
|
@ -1,6 +1,7 @@
|
|||
from tgbot.api import send_message, forward_message, delete_message, \
|
||||
ban_member, unban_member, mute_member, unmute_member, \
|
||||
approve_chat_join_request
|
||||
approve_chat_join_request, send_graph
|
||||
from tgbot.graph import generate_chart
|
||||
from tgbot.config import REDIS_URL, FEEDBACK_CHAT_ID, BUTTON_VOUCH, NEWCOMER_MSG
|
||||
import json
|
||||
import redis
|
||||
|
@ -13,7 +14,7 @@ storage = redis.from_url(REDIS_URL)
|
|||
# хранение необходимой информации о пользователях
|
||||
Profile = ProfileObj(storage)
|
||||
|
||||
def show_request_msg(msg):
|
||||
def newcomer_show(msg):
|
||||
reply_markup = {
|
||||
"inline_keyboard": [
|
||||
[
|
||||
|
@ -24,10 +25,12 @@ def show_request_msg(msg):
|
|||
]
|
||||
]
|
||||
}
|
||||
|
||||
identity = f"{msg['from']['first_name']} {msg['from'].get('last_name', '')}"
|
||||
if 'username' in msg['from']:
|
||||
identity += f" @{msg['from']['username']}"
|
||||
r = send_message(
|
||||
msg['chat']['id'],
|
||||
NEWCOMER_MSG + f"{msg['from']['first_name']} {msg['from']['last_name']}({msg['from']['username']})",
|
||||
NEWCOMER_MSG + identity,
|
||||
reply_to=msg['message_id'],
|
||||
reply_markup=reply_markup
|
||||
)
|
||||
|
@ -67,11 +70,15 @@ def handle_join(msg):
|
|||
|
||||
actor["name"] = msg['from']['first_name'] + msg['from'].get('last_name', '')
|
||||
actor["mention"] = msg['from'].get('username', '')
|
||||
|
||||
if from_id == str(msg['new_chat_member']['id']):
|
||||
newcomer_id = str(msg['new_chat_member']['id'])
|
||||
if from_id == newcomer_id:
|
||||
if len(actor['parents']) == 0:
|
||||
# показываем сообщение с кнопкой "поручиться"
|
||||
welcome_msg_id = show_request_msg(msg)
|
||||
welcome_msg_id = newcomer_show(msg)
|
||||
|
||||
# до одобрения - мьют
|
||||
r = mute_member(chat_id, newcomer_id)
|
||||
print(r.json())
|
||||
|
||||
# обновляем профиль присоединившегося
|
||||
actor['welcome_id'] = welcome_msg_id
|
||||
|
@ -88,6 +95,8 @@ def handle_join(msg):
|
|||
newcomer['parents'].append(from_id)
|
||||
Profile.save(newcomer)
|
||||
actor['children'].append(m['id'])
|
||||
r = unmute_member(chat_id, newcomer['id'])
|
||||
print(r.json())
|
||||
|
||||
# обновляем профиль пригласившего
|
||||
Profile.save(actor)
|
||||
|
@ -118,7 +127,7 @@ def handle_button(callback_query):
|
|||
|
||||
newcomer_id = callback_data[len(BUTTON_VOUCH):]
|
||||
newcomer = Profile.get(newcomer_id)
|
||||
if newcomer_id not in inviter['children'] and \
|
||||
if newcomer_id not in actor['children'] and \
|
||||
actor_id not in newcomer['parents']:
|
||||
newcomer['parents'].append(newcomer_id)
|
||||
actor['children'].append(actor_id)
|
||||
|
@ -127,13 +136,14 @@ def handle_button(callback_query):
|
|||
try:
|
||||
chat_id = str(callback_query['message']['chat']['id'])
|
||||
|
||||
print('accept join request for public chat')
|
||||
r = approve_chat_join_request(chat_id, newcomer_id)
|
||||
print(r.json())
|
||||
|
||||
print('unmute newcomer')
|
||||
r = unmute_member(chat_id, newcomer_id)
|
||||
print(r.json())
|
||||
|
||||
print('accept join request')
|
||||
r = approve_chat_join_request(chat_id, newcomer_id)
|
||||
print(r.json())
|
||||
|
||||
except:
|
||||
pass
|
||||
|
||||
|
@ -150,4 +160,26 @@ def handle_join_request(update):
|
|||
if from_id == str(update['message']['new_chat_member']['id']):
|
||||
if len(actor['parents']) == 0:
|
||||
# показываем сообщение с кнопкой "поручиться"
|
||||
welcome_msg_id = show_request_msg(update)
|
||||
welcome_msg_id = show_request_msg(update)
|
||||
|
||||
|
||||
def handle_graph(_msg):
|
||||
cursor = 0
|
||||
keys = []
|
||||
while True:
|
||||
# Scan for keys starting with 'urs-*' in batches of 100
|
||||
cursor, batch_keys = r.scan(cursor=cursor, match='urs-*', count=100)
|
||||
keys += batch_keys
|
||||
# If the cursor is 0, then we've reached the end of the keys
|
||||
if cursor == 0:
|
||||
break
|
||||
# Get the values of all the keys
|
||||
values = r.mget(keys)
|
||||
# Parse the JSON data from each value
|
||||
members = []
|
||||
for value in values:
|
||||
member = json.loads(value)
|
||||
members.append(member)
|
||||
png_data = generate_chart(values)
|
||||
r = send_graph(png_data, chat_id)
|
||||
print(r.json())
|
||||
|
|
|
@ -19,10 +19,14 @@ class Profile:
|
|||
return s
|
||||
|
||||
def save(self, s):
|
||||
self.storage.set(f'usr-{member_id}', json.dumps(s))
|
||||
self.storage.set(f'usr-{s["id"]}', json.dumps(s))
|
||||
|
||||
def get(self, member_id):
|
||||
return json.loads(self.storage.get(f'usr-{member_id}')) or self.create_session(member_id)
|
||||
data = self.storage.get(f'usr-{member_id}')
|
||||
if data is None:
|
||||
return self.create(member_id)
|
||||
else:
|
||||
return json.loads(data)
|
||||
|
||||
def leaving(self, s):
|
||||
if len(s['parents']) == 0:
|
||||
|
|
Loading…
Reference in New Issue
Block a user