mirror of
https://gitflic.ru/project/maks1ms/ocab.git
synced 2025-04-03 16:13:46 +03:00
убрал legacy модули и отрефакторил admin, filters
This commit is contained in:
parent
4a609db595
commit
212c2836c9
115
scripts/module.py
Normal file
115
scripts/module.py
Normal file
@ -0,0 +1,115 @@
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
|
||||
DEFAULTS = {
|
||||
"description": "Очень полезный модуль",
|
||||
"author": "OCAB Team",
|
||||
"version": "1.0.0",
|
||||
"privileged": "false",
|
||||
}
|
||||
|
||||
|
||||
def create_module(args):
|
||||
module_dir = os.path.join("src/ocab_modules/standard", args.module_name)
|
||||
os.makedirs(module_dir, exist_ok=True)
|
||||
|
||||
module_info = {
|
||||
"id": args.id,
|
||||
"name": args.name,
|
||||
"description": args.description,
|
||||
"author": args.author,
|
||||
"version": args.version,
|
||||
"privileged": args.privileged.lower() == "true",
|
||||
"dependencies": {},
|
||||
}
|
||||
|
||||
with open(os.path.join(module_dir, "info.json"), "w", encoding="utf-8") as f:
|
||||
json.dump(module_info, f, ensure_ascii=False, indent=4)
|
||||
|
||||
with open(os.path.join(module_dir, "__init__.py"), "w", encoding="utf-8") as f:
|
||||
f.write("# Init file for the module\n")
|
||||
|
||||
print(f"Module {args.module_name} created successfully.")
|
||||
|
||||
|
||||
def interactive_mode(args):
|
||||
def get_input(prompt, default=None):
|
||||
if default:
|
||||
value = input(f"{prompt} [{default}]: ")
|
||||
return value if value else default
|
||||
else:
|
||||
value = input(f"{prompt}: ")
|
||||
return value
|
||||
|
||||
module_name = get_input("Введите название модуля (папки)")
|
||||
module_id = get_input("Введите ID")
|
||||
name = get_input("Введите название модуля")
|
||||
description = get_input(
|
||||
"Введите описание модуля", args.description or DEFAULTS["description"]
|
||||
)
|
||||
author = get_input("Введите автора", args.author or DEFAULTS["author"])
|
||||
version = get_input("Введите версию", args.version or DEFAULTS["version"])
|
||||
privileged = get_input(
|
||||
"Модуль привилегированный (true/false)",
|
||||
args.privileged or DEFAULTS["privileged"],
|
||||
)
|
||||
|
||||
args = argparse.Namespace(
|
||||
command="create",
|
||||
module_name=module_name,
|
||||
id=module_id,
|
||||
name=name,
|
||||
description=description,
|
||||
author=author,
|
||||
version=version,
|
||||
privileged=privileged,
|
||||
dependencies="",
|
||||
)
|
||||
|
||||
create_module(args)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Утилита для создания директории модуля с файлами."
|
||||
)
|
||||
subparsers = parser.add_subparsers(dest="command", required=True)
|
||||
|
||||
create_parser = subparsers.add_parser("create", help="Создать новый модуль")
|
||||
create_parser.add_argument("--module_name", help="Название директории модуля")
|
||||
create_parser.add_argument("--id", help="ID модуля")
|
||||
create_parser.add_argument("--name", help="Название модуля")
|
||||
create_parser.add_argument("--description", help="Описание модуля")
|
||||
create_parser.add_argument("--author", help="Автор модуля")
|
||||
create_parser.add_argument("--version", help="Версия модуля")
|
||||
create_parser.add_argument(
|
||||
"--privileged", help="Привилегированный модуль (true/false)"
|
||||
)
|
||||
create_parser.add_argument(
|
||||
"--dependencies", help="Список зависимостей в формате имя:версия через запятую"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.command == "create":
|
||||
if not all(
|
||||
[
|
||||
args.module_name,
|
||||
args.id,
|
||||
args.name,
|
||||
args.description,
|
||||
args.author,
|
||||
args.version,
|
||||
args.privileged,
|
||||
args.dependencies,
|
||||
]
|
||||
):
|
||||
print("Переход в интерактивный режим...")
|
||||
interactive_mode(args)
|
||||
else:
|
||||
create_module(args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -17,6 +17,7 @@ bot_modules = [
|
||||
UnsafeFSLoader(f"{paths.modules_standard}/roles"),
|
||||
FSLoader(f"{paths.modules_standard}/command_helper"),
|
||||
FSLoader(f"{paths.modules_standard}/info"),
|
||||
FSLoader(f"{paths.modules_standard}/filters"),
|
||||
FSLoader(f"{paths.modules_standard}/create_report_apps"),
|
||||
FSLoader(f"{paths.modules_standard}/admin"),
|
||||
]
|
||||
|
@ -3,12 +3,12 @@ from pathlib import Path
|
||||
|
||||
from RestrictedPython import compile_restricted_exec
|
||||
|
||||
from ocab_core.modules_system.loaders.fs_loader.policy import (
|
||||
from ocab_core.modules_system.loaders.unsafe_fs_loader import UnsafeFSLoader
|
||||
from ocab_core.modules_system.safe.policy import (
|
||||
ALLOWED_IMPORTS,
|
||||
BUILTINS,
|
||||
RestrictedPythonPolicy,
|
||||
)
|
||||
from ocab_core.modules_system.loaders.unsafe_fs_loader import UnsafeFSLoader
|
||||
|
||||
|
||||
class FSLoader(UnsafeFSLoader):
|
||||
|
@ -1,9 +1,8 @@
|
||||
from ocab_core.logger import log # noqa
|
||||
|
||||
from .public_api import (
|
||||
Storage,
|
||||
get_fsm_context,
|
||||
get_module,
|
||||
log,
|
||||
register_outer_message_middleware,
|
||||
register_router,
|
||||
set_my_commands,
|
||||
|
@ -5,8 +5,11 @@ from aiogram import BaseMiddleware, Router
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.fsm.storage.base import StorageKey
|
||||
|
||||
from ocab_core.logger import log_new
|
||||
from ocab_core.singleton import Singleton
|
||||
|
||||
log = log_new
|
||||
|
||||
|
||||
def register_router(router: Router):
|
||||
app = Singleton()
|
||||
|
@ -9,9 +9,14 @@ from RestrictedPython import (
|
||||
utility_builtins,
|
||||
)
|
||||
from RestrictedPython.Eval import default_guarded_getitem, default_guarded_getiter
|
||||
from RestrictedPython.Guards import full_write_guard, safer_getattr
|
||||
from RestrictedPython.Guards import (
|
||||
full_write_guard,
|
||||
guarded_unpack_sequence,
|
||||
safer_getattr,
|
||||
)
|
||||
|
||||
from ocab_core.logger import log_new
|
||||
from ocab_core.modules_system.safe.zope_guards import extra_safe_builtins
|
||||
|
||||
|
||||
class RestrictedPythonPolicy(RestrictingNodeTransformer):
|
||||
@ -83,7 +88,6 @@ ALLOWED_IMPORTS = [
|
||||
|
||||
|
||||
def safes_getattr(object, name, default=None, getattr=safer_getattr):
|
||||
|
||||
if isinstance(object, Bot) and name == "token":
|
||||
log_new("Bot.token is not allowed")
|
||||
raise Exception("Bot.token is not allowed")
|
||||
@ -94,21 +98,12 @@ def safes_getattr(object, name, default=None, getattr=safer_getattr):
|
||||
BUILTINS = safe_builtins.copy()
|
||||
BUILTINS.update(utility_builtins)
|
||||
BUILTINS.update(limited_builtins)
|
||||
BUILTINS.update(extra_safe_builtins)
|
||||
BUILTINS["__metaclass__"] = _metaclass
|
||||
BUILTINS["_getitem_"] = default_guarded_getitem
|
||||
BUILTINS["_getattr_"] = safes_getattr
|
||||
BUILTINS["_getiter_"] = default_guarded_getiter
|
||||
BUILTINS["_write_"] = full_write_guard
|
||||
BUILTINS["_unpack_sequence_"] = guarded_unpack_sequence
|
||||
BUILTINS["staticmethod"] = staticmethod
|
||||
|
||||
|
||||
class GuardedDictType:
|
||||
def __call__(self, *args, **kwargs):
|
||||
return dict(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def fromkeys(iterable, value=None):
|
||||
return dict.fromkeys(iterable, value)
|
||||
|
||||
|
||||
BUILTINS["dict"] = GuardedDictType()
|
||||
BUILTINS["tuple"] = tuple
|
111
src/ocab_core/modules_system/safe/zope_guards.py
Normal file
111
src/ocab_core/modules_system/safe/zope_guards.py
Normal file
@ -0,0 +1,111 @@
|
||||
#############################################################################
|
||||
#
|
||||
# Copyright (c) 2024 OCAB Team
|
||||
# Copyright (c) 2002 Zope Foundation and Contributors.
|
||||
#
|
||||
# This software includes a function derived from the software subject to the
|
||||
# provisions of the Zope Public License, Version 2.1 (ZPL). A copy of the ZPL
|
||||
# should accompany this distribution. THIS SOFTWARE IS PROVIDED "AS IS" AND ANY
|
||||
# AND ALL EXPRESS OR IMPLIED WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST
|
||||
# INFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
extra_safe_builtins = {}
|
||||
|
||||
|
||||
class GuardedDictType:
|
||||
def __call__(self, *args, **kwargs):
|
||||
return dict(*args, **kwargs)
|
||||
|
||||
def fromkeys(self, S, v=None):
|
||||
return dict.fromkeys(S, v)
|
||||
|
||||
|
||||
extra_safe_builtins["dict"] = GuardedDictType()
|
||||
|
||||
|
||||
ContainerAssertions = {
|
||||
type(()): 1,
|
||||
bytes: 1,
|
||||
str: 1,
|
||||
range: 1,
|
||||
}
|
||||
|
||||
Containers = ContainerAssertions.get
|
||||
|
||||
|
||||
def _error(index):
|
||||
raise Exception("unauthorized access to element")
|
||||
|
||||
|
||||
def guard(container, value, index=None):
|
||||
# if Containers(type(container)) and Containers(type(value)):
|
||||
# # Simple type. Short circuit.
|
||||
# return
|
||||
# I don't know how to do this.
|
||||
# if getSecurityManager().validate(container, container, index, value):
|
||||
# return
|
||||
# _error(index)
|
||||
return
|
||||
|
||||
|
||||
class SafeIter:
|
||||
__allow_access_to_unprotected_subobjects__ = 1
|
||||
|
||||
def __init__(self, ob, container=None):
|
||||
self._iter = iter(ob)
|
||||
if container is None:
|
||||
container = ob
|
||||
self.container = container
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
ob = next(self._iter)
|
||||
guard(self.container, ob)
|
||||
return ob
|
||||
|
||||
next = __next__
|
||||
|
||||
|
||||
class NullIter(SafeIter):
|
||||
def __init__(self, ob):
|
||||
self._iter = ob
|
||||
|
||||
def __next__(self):
|
||||
return next(self._iter)
|
||||
|
||||
next = __next__
|
||||
|
||||
|
||||
def guarded_iter(*args):
|
||||
if len(args) == 1:
|
||||
i = args[0]
|
||||
# Don't double-wrap
|
||||
if isinstance(i, SafeIter):
|
||||
return i
|
||||
if not isinstance(i, range):
|
||||
return SafeIter(i)
|
||||
# Other call styles / targets don't need to be guarded
|
||||
return NullIter(iter(*args))
|
||||
|
||||
|
||||
extra_safe_builtins["iter"] = guarded_iter
|
||||
|
||||
|
||||
def guarded_any(seq):
|
||||
return any(guarded_iter(seq))
|
||||
|
||||
|
||||
extra_safe_builtins["any"] = guarded_any
|
||||
|
||||
|
||||
def guarded_all(seq):
|
||||
return all(guarded_iter(seq))
|
||||
|
||||
|
||||
extra_safe_builtins["all"] = guarded_all
|
@ -1,8 +1,5 @@
|
||||
from aiogram import Dispatcher
|
||||
|
||||
from src.ocab_modules.standard.admin.routers import router as admin_router
|
||||
|
||||
# from src.modules.standard.info.routers import router as info_router
|
||||
from src.ocab_modules.standard.message_processing.message_api import (
|
||||
router as process_message,
|
||||
)
|
||||
@ -14,5 +11,5 @@ async def include_routers(dp: Dispatcher):
|
||||
dp.include_router()
|
||||
"""
|
||||
# dp.include_router(info_router)
|
||||
dp.include_router(admin_router)
|
||||
# dp.include_router(admin_router)
|
||||
dp.include_router(process_message)
|
||||
|
@ -6,8 +6,8 @@ import time
|
||||
import aiogram
|
||||
import aiohttp
|
||||
|
||||
from ...standard.config.config import *
|
||||
from ...standard.roles.roles import *
|
||||
from ocab_modules.standard.config.config import *
|
||||
from ocab_modules.standard.roles.roles import *
|
||||
|
||||
|
||||
class Moderation:
|
@ -5,18 +5,12 @@ import random
|
||||
from threading import Thread
|
||||
|
||||
from aiogram import Bot
|
||||
from aiogram.types import Message
|
||||
from aiogram.types import inline_keyboard_button as types
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
|
||||
from ocab_modules.legacy.moderation import ban_user, unmute_user
|
||||
from src.ocab_modules.standard.config.config import get_telegram_check_bot
|
||||
from src.ocab_modules.standard.database.db_api import *
|
||||
from src.ocab_modules.standard.moderation.moderation import (
|
||||
ban_user,
|
||||
mute_user,
|
||||
unmute_user,
|
||||
)
|
||||
from src.ocab_modules.standard.roles.roles import Roles
|
||||
|
||||
|
||||
async def create_math_task():
|
@ -1,6 +1,6 @@
|
||||
from aiogram import F, Router
|
||||
|
||||
from src.ocab_modules.standard.welcome.handlers import check_new_user
|
||||
from ocab_modules.legacy.welcome.handlers import check_new_user
|
||||
|
||||
router = Router()
|
||||
|
@ -1 +1 @@
|
||||
from . import routers
|
||||
from .main import module_init
|
||||
|
@ -1,10 +1,10 @@
|
||||
# flake8: noqa
|
||||
import time
|
||||
|
||||
from aiogram import Bot
|
||||
from aiogram.types import Message
|
||||
|
||||
from src.ocab_modules.standard.config.config import get_default_chat_tag
|
||||
from ocab_core.modules_system.public_api import get_module
|
||||
|
||||
get_default_chat_tag = get_module("standard.config", "get_default_chat_tag")
|
||||
|
||||
|
||||
async def delete_message(message: Message, bot: Bot):
|
||||
|
@ -1,6 +1,11 @@
|
||||
{
|
||||
"id": "standard.admin",
|
||||
"name": "Admin",
|
||||
"description": "Модуль для работы с админкой",
|
||||
"author": "OCAB Team",
|
||||
"version": "1.0"
|
||||
"version": "1.0.0",
|
||||
"privileged": false,
|
||||
"dependencies": {
|
||||
"standard.filters": "^1.0.0"
|
||||
}
|
||||
}
|
||||
|
7
src/ocab_modules/standard/admin/main.py
Normal file
7
src/ocab_modules/standard/admin/main.py
Normal file
@ -0,0 +1,7 @@
|
||||
from ocab_core.modules_system.public_api import register_router
|
||||
|
||||
from .routers import router
|
||||
|
||||
|
||||
async def module_init():
|
||||
register_router(router)
|
@ -1,24 +1,30 @@
|
||||
# flake8: noqa
|
||||
from aiogram import F, Router
|
||||
from aiogram.filters import Command
|
||||
|
||||
from src.ocab_modules.standard.admin.handlers import (
|
||||
from ocab_core.modules_system.public_api import get_module, log
|
||||
|
||||
from .handlers import (
|
||||
chat_not_in_approve_list,
|
||||
delete_message,
|
||||
error_access,
|
||||
get_chat_id,
|
||||
)
|
||||
from src.ocab_modules.standard.filters.filters import (
|
||||
ChatModerOrAdminFilter,
|
||||
ChatNotInApproveFilter,
|
||||
|
||||
(ChatModerOrAdminFilter, ChatNotInApproveFilter) = get_module(
|
||||
"standard.filters", ["ChatModerOrAdminFilter", "ChatNotInApproveFilter"]
|
||||
)
|
||||
|
||||
log(ChatModerOrAdminFilter)
|
||||
log(ChatNotInApproveFilter)
|
||||
|
||||
router = Router()
|
||||
|
||||
# Если сообщение содержит какой либо текст и выполняется фильтр ChatNotInApproveFilter, то вызывается функция chat_not_in_approve_list
|
||||
router.message.register(chat_not_in_approve_list, ChatNotInApproveFilter(), F.text)
|
||||
|
||||
router.message.register(get_chat_id, ChatModerOrAdminFilter(), F.text == "/chatID")
|
||||
router.message.register(get_chat_id, ChatModerOrAdminFilter(), Command("chatID"))
|
||||
|
||||
router.message.register(delete_message, ChatModerOrAdminFilter(), F.text == "/rm")
|
||||
router.message.register(error_access, F.text == "/rm")
|
||||
router.message.register(error_access, F.text == "/chatID")
|
||||
router.message.register(delete_message, ChatModerOrAdminFilter(), Command("rm"))
|
||||
router.message.register(error_access, Command("rm"))
|
||||
router.message.register(error_access, Command("chatID"))
|
||||
|
@ -1 +1 @@
|
||||
from .main import module_init, module_late_init, register_command
|
||||
from .main import module_init, register_command
|
||||
|
@ -1 +1 @@
|
||||
from .config import config
|
||||
from .config import get_approved_chat_id, get_default_chat_tag, get_roles
|
||||
|
@ -27,13 +27,17 @@ def get_telegram_check_bot() -> bool:
|
||||
return config["TELEGRAM"]["CHECK_BOT"]
|
||||
|
||||
|
||||
def get_aproved_chat_id() -> list:
|
||||
def get_approved_chat_id() -> list:
|
||||
# Возваращем сплитованный список id чатов в формате int
|
||||
return [
|
||||
int(chat_id) for chat_id in config["TELEGRAM"]["APPROVED_CHAT_ID"].split(" | ")
|
||||
]
|
||||
|
||||
|
||||
def get_roles():
|
||||
return config["ROLES"]
|
||||
|
||||
|
||||
def get_user_role_name(role_number) -> dict:
|
||||
# Возвращаем название роли пользвателя по номеру роли, если такой роли нет, возвращаем неизвестно
|
||||
return config["ROLES"].get(role_number, "Неизвестно")
|
||||
|
@ -0,0 +1 @@
|
||||
from .filters import ChatModerOrAdminFilter, ChatNotInApproveFilter
|
@ -2,9 +2,10 @@ from aiogram import Bot
|
||||
from aiogram.filters import BaseFilter
|
||||
from aiogram.types import Message
|
||||
|
||||
from ocab_core.logger import log
|
||||
from ocab_modules.standard.config.config import get_aproved_chat_id
|
||||
from ocab_modules.standard.roles.roles import Roles
|
||||
from ocab_core.modules_system.public_api import get_module, log
|
||||
|
||||
get_approved_chat_id = get_module("standard.config", "get_approved_chat_id")
|
||||
Roles = get_module("standard.roles", "Roles")
|
||||
|
||||
|
||||
class ChatModerOrAdminFilter(BaseFilter):
|
||||
@ -21,14 +22,11 @@ class ChatModerOrAdminFilter(BaseFilter):
|
||||
|
||||
class ChatNotInApproveFilter(BaseFilter):
|
||||
async def __call__(self, message: Message, bot: Bot) -> bool:
|
||||
# print("chat_check")
|
||||
await log("chat_check")
|
||||
log("chat_check")
|
||||
chat_id = message.chat.id
|
||||
if chat_id in get_aproved_chat_id():
|
||||
# print(f"Chat in approve list: {chat_id}")
|
||||
await log(f"Chat in approve list: {chat_id}")
|
||||
if chat_id in get_approved_chat_id():
|
||||
log(f"Chat in approve list: {chat_id}")
|
||||
return False
|
||||
else:
|
||||
# print(f"Chat not in approve list: {chat_id}")
|
||||
await log(f"Chat not in approve list: {chat_id}")
|
||||
log(f"Chat not in approve list: {chat_id}")
|
||||
return True
|
||||
|
@ -1,6 +1,12 @@
|
||||
{
|
||||
"id": "standard.filters",
|
||||
"name": "Filters",
|
||||
"description": "Модуль с фильтрами",
|
||||
"author": "OCAB Team",
|
||||
"version": "1.0"
|
||||
"version": "1.0.0",
|
||||
"privileged": false,
|
||||
"dependencies": {
|
||||
"standard.roles": "^1.0.0",
|
||||
"standard.config": "^1.0.0"
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ from aiogram import Bot, F, Router, types
|
||||
from ocab_core.logger import log
|
||||
from ocab_modules.external.yandexgpt.handlers import answer_to_message
|
||||
from ocab_modules.standard.config.config import (
|
||||
get_aproved_chat_id,
|
||||
get_approved_chat_id,
|
||||
get_yandexgpt_in_words,
|
||||
get_yandexgpt_start_words,
|
||||
)
|
||||
@ -17,7 +17,7 @@ async def chat_check(message: types.Message):
|
||||
# Если чата нет в базе данных, то проверяем его в наличии в конфиге и если он там есть то добавляем его в БД
|
||||
# Если чат есть в базе данных, то pass
|
||||
if get_chat(message.chat.id) is None:
|
||||
if message.chat.id in get_aproved_chat_id():
|
||||
if message.chat.id in get_approved_chat_id():
|
||||
# print(f"Chat in approve list: {message.chat.id} {message.chat.title}")
|
||||
await log(f"Chat in approve list: {message.chat.id} {message.chat.title}")
|
||||
add_chat(message.chat.id, message.chat.title)
|
||||
|
@ -1,7 +1,9 @@
|
||||
from ocab_core.modules_system.public_api import get_module
|
||||
|
||||
get_user_role = get_module("standard.database", "db_api.get_user_role")
|
||||
config: dict = get_module("standard.config", "config")
|
||||
get_roles = get_module("standard.config", "get_roles")
|
||||
|
||||
roles = get_roles()
|
||||
|
||||
|
||||
class Roles:
|
||||
@ -9,13 +11,12 @@ class Roles:
|
||||
moderator = "MODERATOR"
|
||||
admin = "ADMIN"
|
||||
bot = "BOT"
|
||||
__roles = config["ROLES"]
|
||||
|
||||
def __init__(self):
|
||||
self.user_role_id = self.__roles[self.user]
|
||||
self.moderator_role_id = self.__roles[self.moderator]
|
||||
self.admin_role_id = self.__roles[self.admin]
|
||||
self.bot_role_id = self.__roles[self.bot]
|
||||
self.user_role_id = roles[self.user]
|
||||
self.moderator_role_id = roles[self.moderator]
|
||||
self.admin_role_id = roles[self.admin]
|
||||
self.bot_role_id = roles[self.bot]
|
||||
|
||||
async def check_admin_permission(self, user_id):
|
||||
match get_user_role(user_id):
|
||||
|
Loading…
Reference in New Issue
Block a user