From 7c196371c0c2de3c84d1d1ffd8a677cc8b6369b7 Mon Sep 17 00:00:00 2001 From: Maxim Slipenko Date: Tue, 20 Aug 2024 16:56:50 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D1=8C=20=D1=81=D0=BE=20?= =?UTF-8?q?=D1=81=D1=82=D0=B0=D1=82=D0=B8=D1=81=D1=82=D0=B8=D0=BA=D0=BE?= =?UTF-8?q?=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gnomik/gnomik/__main__.py | 9 +- .../standard/statistics/__init__.py | 15 + .../standard/statistics/db/__init__.py | 1 + .../standard/statistics/db/piccolo_app.py | 15 + .../db/piccolo_migrations/__init__.py | 0 ...rdstatistics_2024_08_20t16_28_38_371951.py | 322 ++++++++++++++++++ .../standard/statistics/db/tables.py | 34 ++ .../standard/statistics/info.json | 18 + .../karkas_blocks/standard/statistics/main.py | 68 ++++ 9 files changed, 474 insertions(+), 8 deletions(-) create mode 100644 src/karkas_blocks/karkas_blocks/standard/statistics/__init__.py create mode 100644 src/karkas_blocks/karkas_blocks/standard/statistics/db/__init__.py create mode 100644 src/karkas_blocks/karkas_blocks/standard/statistics/db/piccolo_app.py create mode 100644 src/karkas_blocks/karkas_blocks/standard/statistics/db/piccolo_migrations/__init__.py create mode 100644 src/karkas_blocks/karkas_blocks/standard/statistics/db/piccolo_migrations/standardstatistics_2024_08_20t16_28_38_371951.py create mode 100644 src/karkas_blocks/karkas_blocks/standard/statistics/db/tables.py create mode 100644 src/karkas_blocks/karkas_blocks/standard/statistics/info.json create mode 100644 src/karkas_blocks/karkas_blocks/standard/statistics/main.py diff --git a/src/gnomik/gnomik/__main__.py b/src/gnomik/gnomik/__main__.py index e4f17f0..ea26330 100644 --- a/src/gnomik/gnomik/__main__.py +++ b/src/gnomik/gnomik/__main__.py @@ -10,23 +10,16 @@ async def main(): [ block_loader("standard", "config", safe=False), block_loader("standard", "database", safe=False), + block_loader("standard", "statistics", safe=False), block_loader("standard", "command_helper"), block_loader("standard", "roles", safe=False), block_loader("standard", "fsm_database_storage", safe=False), block_loader("external", "create_report_apps"), - # block_loader("experimental", "message_db_logger", safe=False), block_loader("standard", "info"), block_loader("standard", "help"), - # block_loader("standard", "config", safe=False), - # block_loader("standard", "database", safe=False), - # block_loader("standard", "fsm_database_storage", safe=False), - # block_loader("standard", "roles", safe=False), # block_loader("external", "yandexgpt", safe=False), # - # block_loader("standard", "command_helper"), - # block_loader("standard", "info"), # block_loader("standard", "filters"), - # block_loader("external", "create_report_apps"), # block_loader("standard", "admin"), # block_loader("standard", "message_processing"), # block_loader("standard", "miniapp", safe=False), diff --git a/src/karkas_blocks/karkas_blocks/standard/statistics/__init__.py b/src/karkas_blocks/karkas_blocks/standard/statistics/__init__.py new file mode 100644 index 0000000..ab5e22e --- /dev/null +++ b/src/karkas_blocks/karkas_blocks/standard/statistics/__init__.py @@ -0,0 +1,15 @@ +from karkas_core.modules_system.public_api import ( + get_module, + register_outer_message_middleware, +) + +from .main import StatisticsMiddleware + + +def module_init(): + register_app_config = get_module("standard.database", "register_app_config") + from .db import APP_CONFIG + + register_app_config(APP_CONFIG) + + register_outer_message_middleware(StatisticsMiddleware()) diff --git a/src/karkas_blocks/karkas_blocks/standard/statistics/db/__init__.py b/src/karkas_blocks/karkas_blocks/standard/statistics/db/__init__.py new file mode 100644 index 0000000..e3e4a0b --- /dev/null +++ b/src/karkas_blocks/karkas_blocks/standard/statistics/db/__init__.py @@ -0,0 +1 @@ +from .piccolo_app import APP_CONFIG diff --git a/src/karkas_blocks/karkas_blocks/standard/statistics/db/piccolo_app.py b/src/karkas_blocks/karkas_blocks/standard/statistics/db/piccolo_app.py new file mode 100644 index 0000000..5af5bd2 --- /dev/null +++ b/src/karkas_blocks/karkas_blocks/standard/statistics/db/piccolo_app.py @@ -0,0 +1,15 @@ +import os + +from karkas_piccolo.conf.apps import AppConfig + +from .tables import ChatStats, Messages, UserStats + +CURRENT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) + +APP_CONFIG = AppConfig( + app_name="standard.statistics", + migrations_folder_path=os.path.join(CURRENT_DIRECTORY, "piccolo_migrations"), + table_classes=[ChatStats, Messages, UserStats], + migration_dependencies=[], + commands=[], +) diff --git a/src/karkas_blocks/karkas_blocks/standard/statistics/db/piccolo_migrations/__init__.py b/src/karkas_blocks/karkas_blocks/standard/statistics/db/piccolo_migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/karkas_blocks/karkas_blocks/standard/statistics/db/piccolo_migrations/standardstatistics_2024_08_20t16_28_38_371951.py b/src/karkas_blocks/karkas_blocks/standard/statistics/db/piccolo_migrations/standardstatistics_2024_08_20t16_28_38_371951.py new file mode 100644 index 0000000..bfb98b5 --- /dev/null +++ b/src/karkas_blocks/karkas_blocks/standard/statistics/db/piccolo_migrations/standardstatistics_2024_08_20t16_28_38_371951.py @@ -0,0 +1,322 @@ +from piccolo.apps.migrations.auto.migration_manager import MigrationManager +from piccolo.columns.column_types import Date, Integer, Text +from piccolo.columns.defaults.date import DateNow +from piccolo.columns.indexes import IndexMethod + +ID = "2024-08-20T16:28:38:371951" +VERSION = "1.16.0" +DESCRIPTION = "" + + +async def forwards(): + manager = MigrationManager( + migration_id=ID, app_name="standard.statistics", description=DESCRIPTION + ) + + manager.add_table( + class_name="Messages", tablename="messages", schema=None, columns=None + ) + + manager.add_table( + class_name="ChatStats", tablename="chat_stats", schema=None, columns=None + ) + + manager.add_table( + class_name="UserStats", tablename="user_stats", schema=None, columns=None + ) + + manager.add_column( + table_class_name="Messages", + tablename="messages", + column_name="key", + db_column_name="key", + column_class_name="Text", + column_class=Text, + params={ + "default": "", + "null": False, + "primary_key": True, + "unique": False, + "index": False, + "index_method": IndexMethod.btree, + "choices": None, + "db_column_name": None, + "secret": False, + }, + schema=None, + ) + + manager.add_column( + table_class_name="Messages", + tablename="messages", + column_name="chat_id", + db_column_name="chat_id", + column_class_name="Integer", + column_class=Integer, + params={ + "default": 0, + "null": False, + "primary_key": False, + "unique": False, + "index": False, + "index_method": IndexMethod.btree, + "choices": None, + "db_column_name": None, + "secret": False, + }, + schema=None, + ) + + manager.add_column( + table_class_name="Messages", + tablename="messages", + column_name="message_id", + db_column_name="message_id", + column_class_name="Integer", + column_class=Integer, + params={ + "default": 0, + "null": False, + "primary_key": False, + "unique": False, + "index": False, + "index_method": IndexMethod.btree, + "choices": None, + "db_column_name": None, + "secret": False, + }, + schema=None, + ) + + manager.add_column( + table_class_name="Messages", + tablename="messages", + column_name="sender_id", + db_column_name="sender_id", + column_class_name="Integer", + column_class=Integer, + params={ + "default": 0, + "null": False, + "primary_key": False, + "unique": False, + "index": False, + "index_method": IndexMethod.btree, + "choices": None, + "db_column_name": None, + "secret": False, + }, + schema=None, + ) + + manager.add_column( + table_class_name="Messages", + tablename="messages", + column_name="answer_to_message_id", + db_column_name="answer_to_message_id", + column_class_name="Integer", + column_class=Integer, + params={ + "default": None, + "null": True, + "primary_key": False, + "unique": False, + "index": False, + "index_method": IndexMethod.btree, + "choices": None, + "db_column_name": None, + "secret": False, + }, + schema=None, + ) + + manager.add_column( + table_class_name="Messages", + tablename="messages", + column_name="message_text", + db_column_name="message_text", + column_class_name="Text", + column_class=Text, + params={ + "default": "", + "null": False, + "primary_key": False, + "unique": False, + "index": False, + "index_method": IndexMethod.btree, + "choices": None, + "db_column_name": None, + "secret": False, + }, + schema=None, + ) + + manager.add_column( + table_class_name="ChatStats", + tablename="chat_stats", + column_name="chat_id", + db_column_name="chat_id", + column_class_name="Integer", + column_class=Integer, + params={ + "default": 0, + "null": False, + "primary_key": True, + "unique": False, + "index": False, + "index_method": IndexMethod.btree, + "choices": None, + "db_column_name": None, + "secret": False, + }, + schema=None, + ) + + manager.add_column( + table_class_name="ChatStats", + tablename="chat_stats", + column_name="date", + db_column_name="date", + column_class_name="Date", + column_class=Date, + params={ + "default": DateNow(), + "null": False, + "primary_key": False, + "unique": False, + "index": False, + "index_method": IndexMethod.btree, + "choices": None, + "db_column_name": None, + "secret": False, + }, + schema=None, + ) + + manager.add_column( + table_class_name="ChatStats", + tablename="chat_stats", + column_name="messages_count", + db_column_name="messages_count", + column_class_name="Integer", + column_class=Integer, + params={ + "default": 0, + "null": False, + "primary_key": False, + "unique": False, + "index": False, + "index_method": IndexMethod.btree, + "choices": None, + "db_column_name": None, + "secret": False, + }, + schema=None, + ) + + manager.add_column( + table_class_name="UserStats", + tablename="user_stats", + column_name="key", + db_column_name="key", + column_class_name="Text", + column_class=Text, + params={ + "default": "", + "null": False, + "primary_key": True, + "unique": False, + "index": False, + "index_method": IndexMethod.btree, + "choices": None, + "db_column_name": None, + "secret": False, + }, + schema=None, + ) + + manager.add_column( + table_class_name="UserStats", + tablename="user_stats", + column_name="chat_id", + db_column_name="chat_id", + column_class_name="Integer", + column_class=Integer, + params={ + "default": 0, + "null": False, + "primary_key": False, + "unique": False, + "index": False, + "index_method": IndexMethod.btree, + "choices": None, + "db_column_name": None, + "secret": False, + }, + schema=None, + ) + + manager.add_column( + table_class_name="UserStats", + tablename="user_stats", + column_name="user_id", + db_column_name="user_id", + column_class_name="Integer", + column_class=Integer, + params={ + "default": 0, + "null": False, + "primary_key": False, + "unique": False, + "index": False, + "index_method": IndexMethod.btree, + "choices": None, + "db_column_name": None, + "secret": False, + }, + schema=None, + ) + + manager.add_column( + table_class_name="UserStats", + tablename="user_stats", + column_name="date", + db_column_name="date", + column_class_name="Date", + column_class=Date, + params={ + "default": DateNow(), + "null": False, + "primary_key": False, + "unique": False, + "index": False, + "index_method": IndexMethod.btree, + "choices": None, + "db_column_name": None, + "secret": False, + }, + schema=None, + ) + + manager.add_column( + table_class_name="UserStats", + tablename="user_stats", + column_name="messages_count", + db_column_name="messages_count", + column_class_name="Integer", + column_class=Integer, + params={ + "default": 0, + "null": False, + "primary_key": False, + "unique": False, + "index": False, + "index_method": IndexMethod.btree, + "choices": None, + "db_column_name": None, + "secret": False, + }, + schema=None, + ) + + return manager diff --git a/src/karkas_blocks/karkas_blocks/standard/statistics/db/tables.py b/src/karkas_blocks/karkas_blocks/standard/statistics/db/tables.py new file mode 100644 index 0000000..dc73184 --- /dev/null +++ b/src/karkas_blocks/karkas_blocks/standard/statistics/db/tables.py @@ -0,0 +1,34 @@ +from piccolo.columns import Date, Integer, Text +from piccolo.table import Table + + +class ChatStats(Table): + chat_id = Integer(primary_key=True) + date = Date() + messages_count = Integer(default=0) + + +class Messages(Table): + # Временная мера, пока не примут + # https://github.com/piccolo-orm/piccolo/pull/984 + # {message_chat_id}-{message_id} + key = Text(primary_key=True) + + chat_id = Integer() + message_id = Integer() + sender_id = Integer() + answer_to_message_id = Integer(null=True, default=None) + # message_ai_model = pw.TextField(null=True) + message_text = Text() + + +class UserStats(Table): + # Временная мера, пока не примут + # https://github.com/piccolo-orm/piccolo/pull/984 + # {chat_id}-{user_id} + key = Text(primary_key=True) + + chat_id = Integer() + user_id = Integer() + date = Date() + messages_count = Integer(default=0) diff --git a/src/karkas_blocks/karkas_blocks/standard/statistics/info.json b/src/karkas_blocks/karkas_blocks/standard/statistics/info.json new file mode 100644 index 0000000..1f3e0d8 --- /dev/null +++ b/src/karkas_blocks/karkas_blocks/standard/statistics/info.json @@ -0,0 +1,18 @@ +{ + "id": "standard.statistics", + "name": "Статистика", + "description": "Очень полезный модуль", + "author": "Karkas Team", + "version": "1.0.0", + "privileged": true, + "dependencies": { + "required": { + "standard.database": "^1.0.0" + } + }, + "pythonDependencies": { + "required": { + "piccolo": "*" + } + } + } diff --git a/src/karkas_blocks/karkas_blocks/standard/statistics/main.py b/src/karkas_blocks/karkas_blocks/standard/statistics/main.py new file mode 100644 index 0000000..7e85deb --- /dev/null +++ b/src/karkas_blocks/karkas_blocks/standard/statistics/main.py @@ -0,0 +1,68 @@ +from typing import Any, Awaitable, Callable, Dict + +from aiogram import BaseMiddleware +from aiogram.types import Message, TelegramObject + +from .db.tables import ChatStats, Messages, UserStats + + +async def update_chat_stats(event: Message): + await ChatStats.insert( + ChatStats(chat_id=event.chat.id, date=event.date, messages_count=1) + ).on_conflict( + action="DO UPDATE", + values=[ + ChatStats.date, + (ChatStats.messages_count, ChatStats.messages_count + 1), + ], + ).run() + + +async def update_user_stats(event: Message): + await UserStats.insert( + UserStats( + key=f"{event.chat.id}-{event.from_user.id}", + chat_id=event.chat.id, + user_id=event.from_user.id, + date=event.date, + messages_count=1, + ) + ).on_conflict( + action="DO UPDATE", + values=[ + UserStats.date, + (UserStats.messages_count, UserStats.messages_count + 1), + ], + ).run() + + +async def save_messages(event: Message): + await Messages.insert( + Messages( + key=f"{event.chat.id}-{event.message_id}", + chat_id=event.chat.id, + message_id=event.message_id, + sender_id=event.from_user.id, + answer_to_message_id=( + event.reply_to_message.message_id if event.reply_to_message else None + ), + message_text=event.text, + ) + ) + + +class StatisticsMiddleware(BaseMiddleware): + async def __call__( + self, + handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]], + event: TelegramObject, + data: Dict[str, Any], + ) -> Any: + + await update_chat_stats(event) + await update_user_stats(event) + await save_messages(event) + + result = await handler(event, data) + + return result