mirror of
				https://gitflic.ru/project/alt-gnome/karkas.git
				synced 2025-11-03 23:12:27 +03:00 
			
		
		
		
	Merged with chore/code-quality-tools
This commit is contained in:
		
							
								
								
									
										6
									
								
								.flake8
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.flake8
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					[flake8]
 | 
				
			||||||
 | 
					per-file-ignores =
 | 
				
			||||||
 | 
					    __init__.py:F401
 | 
				
			||||||
 | 
					max-line-length = 88
 | 
				
			||||||
 | 
					count = true
 | 
				
			||||||
 | 
					extend-ignore = E203,E701
 | 
				
			||||||
							
								
								
									
										30
									
								
								.pre-commit-config.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								.pre-commit-config.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					# See https://pre-commit.com for more information
 | 
				
			||||||
 | 
					# See https://pre-commit.com/hooks.html for more hooks
 | 
				
			||||||
 | 
					repos:
 | 
				
			||||||
 | 
					  - repo: https://github.com/crashappsec/pre-commit-sync
 | 
				
			||||||
 | 
					    rev: 04b0e02eefa7c41bedca7456ad542e60b67c16c6
 | 
				
			||||||
 | 
					    hooks:
 | 
				
			||||||
 | 
					      - id: pre-commit-sync
 | 
				
			||||||
 | 
					  - repo: https://github.com/pre-commit/pre-commit-hooks
 | 
				
			||||||
 | 
					    rev: v3.2.0
 | 
				
			||||||
 | 
					    hooks:
 | 
				
			||||||
 | 
					      - id: trailing-whitespace
 | 
				
			||||||
 | 
					      - id: end-of-file-fixer
 | 
				
			||||||
 | 
					      - id: check-yaml
 | 
				
			||||||
 | 
					      - id: check-added-large-files
 | 
				
			||||||
 | 
					  - repo: https://github.com/PyCQA/isort
 | 
				
			||||||
 | 
					    rev: 5.13.2 # sync:isort:poetry.lock
 | 
				
			||||||
 | 
					    hooks:
 | 
				
			||||||
 | 
					      - id: isort
 | 
				
			||||||
 | 
					  - repo: https://github.com/psf/black
 | 
				
			||||||
 | 
					    rev: 24.4.2 # sync:black:poetry.lock
 | 
				
			||||||
 | 
					    hooks:
 | 
				
			||||||
 | 
					      - id: black
 | 
				
			||||||
 | 
					  - repo: https://github.com/PyCQA/flake8
 | 
				
			||||||
 | 
					    rev: 7.1.0 # sync:flake8:poetry.lock
 | 
				
			||||||
 | 
					    hooks:
 | 
				
			||||||
 | 
					      - id: flake8
 | 
				
			||||||
 | 
					  - repo: https://github.com/PyCQA/bandit
 | 
				
			||||||
 | 
					    rev: 1.7.9 # sync:bandit:poetry.lock
 | 
				
			||||||
 | 
					    hooks:
 | 
				
			||||||
 | 
					      - id: bandit
 | 
				
			||||||
							
								
								
									
										8
									
								
								init.py
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								init.py
									
									
									
									
									
								
							@@ -1,5 +1,5 @@
 | 
				
			|||||||
from pathlib import Path
 | 
					 | 
				
			||||||
from json import dumps
 | 
					from json import dumps
 | 
				
			||||||
 | 
					from pathlib import Path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pwd = Path().cwd()
 | 
					pwd = Path().cwd()
 | 
				
			||||||
dir_core = pwd / "src" / "core"
 | 
					dir_core = pwd / "src" / "core"
 | 
				
			||||||
@@ -7,9 +7,9 @@ dir_modules_standard = pwd / "src" / "modules" / "standard"
 | 
				
			|||||||
dir_modules_custom = pwd / "src" / "modules" / "custom"
 | 
					dir_modules_custom = pwd / "src" / "modules" / "custom"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
json = {
 | 
					json = {
 | 
				
			||||||
    'core': str(dir_core),
 | 
					    "core": str(dir_core),
 | 
				
			||||||
    'modules standard': str(dir_modules_standard),
 | 
					    "modules standard": str(dir_modules_standard),
 | 
				
			||||||
    'modules custom': str(dir_modules_custom),
 | 
					    "modules custom": str(dir_modules_custom),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
with open("src/paths.json", "w", encoding="utf8") as f:
 | 
					with open("src/paths.json", "w", encoding="utf8") as f:
 | 
				
			||||||
    f.write(dumps(json, indent=4))
 | 
					    f.write(dumps(json, indent=4))
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										402
									
								
								poetry.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										402
									
								
								poetry.lock
									
									
									
										generated
									
									
									
								
							@@ -1,4 +1,4 @@
 | 
				
			|||||||
# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
 | 
					# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "aiofiles"
 | 
					name = "aiofiles"
 | 
				
			||||||
@@ -179,6 +179,74 @@ tests = ["attrs[tests-no-zope]", "zope-interface"]
 | 
				
			|||||||
tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"]
 | 
					tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"]
 | 
				
			||||||
tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"]
 | 
					tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "bandit"
 | 
				
			||||||
 | 
					version = "1.7.9"
 | 
				
			||||||
 | 
					description = "Security oriented static analyser for python code."
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.8"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "bandit-1.7.9-py3-none-any.whl", hash = "sha256:52077cb339000f337fb25f7e045995c4ad01511e716e5daac37014b9752de8ec"},
 | 
				
			||||||
 | 
					    {file = "bandit-1.7.9.tar.gz", hash = "sha256:7c395a436743018f7be0a4cbb0a4ea9b902b6d87264ddecf8cfdc73b4f78ff61"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package.dependencies]
 | 
				
			||||||
 | 
					colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""}
 | 
				
			||||||
 | 
					PyYAML = ">=5.3.1"
 | 
				
			||||||
 | 
					rich = "*"
 | 
				
			||||||
 | 
					stevedore = ">=1.20.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package.extras]
 | 
				
			||||||
 | 
					baseline = ["GitPython (>=3.1.30)"]
 | 
				
			||||||
 | 
					sarif = ["jschema-to-python (>=1.2.3)", "sarif-om (>=1.0.4)"]
 | 
				
			||||||
 | 
					test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)"]
 | 
				
			||||||
 | 
					toml = ["tomli (>=1.1.0)"]
 | 
				
			||||||
 | 
					yaml = ["PyYAML"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "black"
 | 
				
			||||||
 | 
					version = "24.4.2"
 | 
				
			||||||
 | 
					description = "The uncompromising code formatter."
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.8"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"},
 | 
				
			||||||
 | 
					    {file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package.dependencies]
 | 
				
			||||||
 | 
					click = ">=8.0.0"
 | 
				
			||||||
 | 
					mypy-extensions = ">=0.4.3"
 | 
				
			||||||
 | 
					packaging = ">=22.0"
 | 
				
			||||||
 | 
					pathspec = ">=0.9.0"
 | 
				
			||||||
 | 
					platformdirs = ">=2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package.extras]
 | 
				
			||||||
 | 
					colorama = ["colorama (>=0.4.3)"]
 | 
				
			||||||
 | 
					d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"]
 | 
				
			||||||
 | 
					jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
 | 
				
			||||||
 | 
					uvloop = ["uvloop (>=0.15.2)"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "certifi"
 | 
					name = "certifi"
 | 
				
			||||||
version = "2024.2.2"
 | 
					version = "2024.2.2"
 | 
				
			||||||
@@ -190,6 +258,17 @@ files = [
 | 
				
			|||||||
    {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"},
 | 
					    {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"},
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "cfgv"
 | 
				
			||||||
 | 
					version = "3.4.0"
 | 
				
			||||||
 | 
					description = "Validate configuration and produce human readable error messages."
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.8"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"},
 | 
				
			||||||
 | 
					    {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "charset-normalizer"
 | 
					name = "charset-normalizer"
 | 
				
			||||||
version = "3.3.2"
 | 
					version = "3.3.2"
 | 
				
			||||||
@@ -289,6 +368,74 @@ files = [
 | 
				
			|||||||
    {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"},
 | 
					    {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"},
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "click"
 | 
				
			||||||
 | 
					version = "8.1.7"
 | 
				
			||||||
 | 
					description = "Composable command line interface toolkit"
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.7"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
 | 
				
			||||||
 | 
					    {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package.dependencies]
 | 
				
			||||||
 | 
					colorama = {version = "*", markers = "platform_system == \"Windows\""}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "colorama"
 | 
				
			||||||
 | 
					version = "0.4.6"
 | 
				
			||||||
 | 
					description = "Cross-platform colored terminal text."
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
 | 
				
			||||||
 | 
					    {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "distlib"
 | 
				
			||||||
 | 
					version = "0.3.8"
 | 
				
			||||||
 | 
					description = "Distribution utilities"
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = "*"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"},
 | 
				
			||||||
 | 
					    {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "filelock"
 | 
				
			||||||
 | 
					version = "3.15.4"
 | 
				
			||||||
 | 
					description = "A platform independent file lock."
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.8"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"},
 | 
				
			||||||
 | 
					    {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package.extras]
 | 
				
			||||||
 | 
					docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
 | 
				
			||||||
 | 
					testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)", "virtualenv (>=20.26.2)"]
 | 
				
			||||||
 | 
					typing = ["typing-extensions (>=4.8)"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "flake8"
 | 
				
			||||||
 | 
					version = "7.1.0"
 | 
				
			||||||
 | 
					description = "the modular source code checker: pep8 pyflakes and co"
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.8.1"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "flake8-7.1.0-py2.py3-none-any.whl", hash = "sha256:2e416edcc62471a64cea09353f4e7bdba32aeb079b6e360554c659a122b1bc6a"},
 | 
				
			||||||
 | 
					    {file = "flake8-7.1.0.tar.gz", hash = "sha256:48a07b626b55236e0fb4784ee69a465fbf59d79eec1f5b4785c3d3bc57d17aa5"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package.dependencies]
 | 
				
			||||||
 | 
					mccabe = ">=0.7.0,<0.8.0"
 | 
				
			||||||
 | 
					pycodestyle = ">=2.12.0,<2.13.0"
 | 
				
			||||||
 | 
					pyflakes = ">=3.2.0,<3.3.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "frozenlist"
 | 
					name = "frozenlist"
 | 
				
			||||||
version = "1.4.1"
 | 
					version = "1.4.1"
 | 
				
			||||||
@@ -375,6 +522,20 @@ files = [
 | 
				
			|||||||
    {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"},
 | 
					    {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"},
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "identify"
 | 
				
			||||||
 | 
					version = "2.5.36"
 | 
				
			||||||
 | 
					description = "File identification library for Python"
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.8"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "identify-2.5.36-py2.py3-none-any.whl", hash = "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa"},
 | 
				
			||||||
 | 
					    {file = "identify-2.5.36.tar.gz", hash = "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package.extras]
 | 
				
			||||||
 | 
					license = ["ukkonen"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "idna"
 | 
					name = "idna"
 | 
				
			||||||
version = "3.7"
 | 
					version = "3.7"
 | 
				
			||||||
@@ -386,6 +547,20 @@ files = [
 | 
				
			|||||||
    {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"},
 | 
					    {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"},
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "isort"
 | 
				
			||||||
 | 
					version = "5.13.2"
 | 
				
			||||||
 | 
					description = "A Python utility / library to sort Python imports."
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.8.0"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"},
 | 
				
			||||||
 | 
					    {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package.extras]
 | 
				
			||||||
 | 
					colors = ["colorama (>=0.4.6)"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "magic-filter"
 | 
					name = "magic-filter"
 | 
				
			||||||
version = "1.0.12"
 | 
					version = "1.0.12"
 | 
				
			||||||
@@ -400,6 +575,52 @@ files = [
 | 
				
			|||||||
[package.extras]
 | 
					[package.extras]
 | 
				
			||||||
dev = ["black (>=22.8.0,<22.9.0)", "flake8 (>=5.0.4,<5.1.0)", "isort (>=5.11.5,<5.12.0)", "mypy (>=1.4.1,<1.5.0)", "pre-commit (>=2.20.0,<2.21.0)", "pytest (>=7.1.3,<7.2.0)", "pytest-cov (>=3.0.0,<3.1.0)", "pytest-html (>=3.1.1,<3.2.0)", "types-setuptools (>=65.3.0,<65.4.0)"]
 | 
					dev = ["black (>=22.8.0,<22.9.0)", "flake8 (>=5.0.4,<5.1.0)", "isort (>=5.11.5,<5.12.0)", "mypy (>=1.4.1,<1.5.0)", "pre-commit (>=2.20.0,<2.21.0)", "pytest (>=7.1.3,<7.2.0)", "pytest-cov (>=3.0.0,<3.1.0)", "pytest-html (>=3.1.1,<3.2.0)", "types-setuptools (>=65.3.0,<65.4.0)"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "markdown-it-py"
 | 
				
			||||||
 | 
					version = "3.0.0"
 | 
				
			||||||
 | 
					description = "Python port of markdown-it. Markdown parsing, done right!"
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.8"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
 | 
				
			||||||
 | 
					    {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package.dependencies]
 | 
				
			||||||
 | 
					mdurl = ">=0.1,<1.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package.extras]
 | 
				
			||||||
 | 
					benchmarking = ["psutil", "pytest", "pytest-benchmark"]
 | 
				
			||||||
 | 
					code-style = ["pre-commit (>=3.0,<4.0)"]
 | 
				
			||||||
 | 
					compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"]
 | 
				
			||||||
 | 
					linkify = ["linkify-it-py (>=1,<3)"]
 | 
				
			||||||
 | 
					plugins = ["mdit-py-plugins"]
 | 
				
			||||||
 | 
					profiling = ["gprof2dot"]
 | 
				
			||||||
 | 
					rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
 | 
				
			||||||
 | 
					testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "mccabe"
 | 
				
			||||||
 | 
					version = "0.7.0"
 | 
				
			||||||
 | 
					description = "McCabe checker, plugin for flake8"
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.6"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
 | 
				
			||||||
 | 
					    {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "mdurl"
 | 
				
			||||||
 | 
					version = "0.1.2"
 | 
				
			||||||
 | 
					description = "Markdown URL utilities"
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.7"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
 | 
				
			||||||
 | 
					    {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "multidict"
 | 
					name = "multidict"
 | 
				
			||||||
version = "6.0.5"
 | 
					version = "6.0.5"
 | 
				
			||||||
@@ -499,6 +720,61 @@ files = [
 | 
				
			|||||||
    {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"},
 | 
					    {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"},
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "mypy-extensions"
 | 
				
			||||||
 | 
					version = "1.0.0"
 | 
				
			||||||
 | 
					description = "Type system extensions for programs checked with the mypy type checker."
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.5"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
 | 
				
			||||||
 | 
					    {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "nodeenv"
 | 
				
			||||||
 | 
					version = "1.9.1"
 | 
				
			||||||
 | 
					description = "Node.js virtual environment builder"
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"},
 | 
				
			||||||
 | 
					    {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "packaging"
 | 
				
			||||||
 | 
					version = "24.1"
 | 
				
			||||||
 | 
					description = "Core utilities for Python packages"
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.8"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
 | 
				
			||||||
 | 
					    {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "pathspec"
 | 
				
			||||||
 | 
					version = "0.12.1"
 | 
				
			||||||
 | 
					description = "Utility library for gitignore style pattern matching of file paths."
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.8"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
 | 
				
			||||||
 | 
					    {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "pbr"
 | 
				
			||||||
 | 
					version = "6.0.0"
 | 
				
			||||||
 | 
					description = "Python Build Reasonableness"
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=2.6"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "pbr-6.0.0-py2.py3-none-any.whl", hash = "sha256:4a7317d5e3b17a3dccb6a8cfe67dab65b20551404c52c8ed41279fa4f0cb4cda"},
 | 
				
			||||||
 | 
					    {file = "pbr-6.0.0.tar.gz", hash = "sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "peewee"
 | 
					name = "peewee"
 | 
				
			||||||
version = "3.17.3"
 | 
					version = "3.17.3"
 | 
				
			||||||
@@ -509,6 +785,51 @@ files = [
 | 
				
			|||||||
    {file = "peewee-3.17.3.tar.gz", hash = "sha256:ef15f90b628e41a584be8306cdc3243c51f73ce88b06154d9572f6d0284a0169"},
 | 
					    {file = "peewee-3.17.3.tar.gz", hash = "sha256:ef15f90b628e41a584be8306cdc3243c51f73ce88b06154d9572f6d0284a0169"},
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "platformdirs"
 | 
				
			||||||
 | 
					version = "4.2.2"
 | 
				
			||||||
 | 
					description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.8"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"},
 | 
				
			||||||
 | 
					    {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package.extras]
 | 
				
			||||||
 | 
					docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
 | 
				
			||||||
 | 
					test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"]
 | 
				
			||||||
 | 
					type = ["mypy (>=1.8)"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "pre-commit"
 | 
				
			||||||
 | 
					version = "3.7.1"
 | 
				
			||||||
 | 
					description = "A framework for managing and maintaining multi-language pre-commit hooks."
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.9"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "pre_commit-3.7.1-py2.py3-none-any.whl", hash = "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5"},
 | 
				
			||||||
 | 
					    {file = "pre_commit-3.7.1.tar.gz", hash = "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package.dependencies]
 | 
				
			||||||
 | 
					cfgv = ">=2.0.0"
 | 
				
			||||||
 | 
					identify = ">=1.0.0"
 | 
				
			||||||
 | 
					nodeenv = ">=0.11.1"
 | 
				
			||||||
 | 
					pyyaml = ">=5.1"
 | 
				
			||||||
 | 
					virtualenv = ">=20.10.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "pycodestyle"
 | 
				
			||||||
 | 
					version = "2.12.0"
 | 
				
			||||||
 | 
					description = "Python style guide checker"
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.8"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "pycodestyle-2.12.0-py2.py3-none-any.whl", hash = "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4"},
 | 
				
			||||||
 | 
					    {file = "pycodestyle-2.12.0.tar.gz", hash = "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "pydantic"
 | 
					name = "pydantic"
 | 
				
			||||||
version = "2.7.1"
 | 
					version = "2.7.1"
 | 
				
			||||||
@@ -619,6 +940,31 @@ files = [
 | 
				
			|||||||
[package.dependencies]
 | 
					[package.dependencies]
 | 
				
			||||||
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
 | 
					typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "pyflakes"
 | 
				
			||||||
 | 
					version = "3.2.0"
 | 
				
			||||||
 | 
					description = "passive checker of Python programs"
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.8"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"},
 | 
				
			||||||
 | 
					    {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "pygments"
 | 
				
			||||||
 | 
					version = "2.18.0"
 | 
				
			||||||
 | 
					description = "Pygments is a syntax highlighting package written in Python."
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.8"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"},
 | 
				
			||||||
 | 
					    {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package.extras]
 | 
				
			||||||
 | 
					windows-terminal = ["colorama (>=0.4.6)"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "pyyaml"
 | 
					name = "pyyaml"
 | 
				
			||||||
version = "6.0.1"
 | 
					version = "6.0.1"
 | 
				
			||||||
@@ -700,6 +1046,38 @@ urllib3 = ">=1.21.1,<3"
 | 
				
			|||||||
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
 | 
					socks = ["PySocks (>=1.5.6,!=1.5.7)"]
 | 
				
			||||||
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
 | 
					use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "rich"
 | 
				
			||||||
 | 
					version = "13.7.1"
 | 
				
			||||||
 | 
					description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.7.0"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"},
 | 
				
			||||||
 | 
					    {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package.dependencies]
 | 
				
			||||||
 | 
					markdown-it-py = ">=2.2.0"
 | 
				
			||||||
 | 
					pygments = ">=2.13.0,<3.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package.extras]
 | 
				
			||||||
 | 
					jupyter = ["ipywidgets (>=7.5.1,<9)"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "stevedore"
 | 
				
			||||||
 | 
					version = "5.2.0"
 | 
				
			||||||
 | 
					description = "Manage dynamic plugins for Python applications"
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.8"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "stevedore-5.2.0-py3-none-any.whl", hash = "sha256:1c15d95766ca0569cad14cb6272d4d31dae66b011a929d7c18219c176ea1b5c9"},
 | 
				
			||||||
 | 
					    {file = "stevedore-5.2.0.tar.gz", hash = "sha256:46b93ca40e1114cea93d738a6c1e365396981bb6bb78c27045b7587c9473544d"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package.dependencies]
 | 
				
			||||||
 | 
					pbr = ">=2.0.0,<2.1.0 || >2.1.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "typing-extensions"
 | 
					name = "typing-extensions"
 | 
				
			||||||
version = "4.11.0"
 | 
					version = "4.11.0"
 | 
				
			||||||
@@ -728,6 +1106,26 @@ h2 = ["h2 (>=4,<5)"]
 | 
				
			|||||||
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
 | 
					socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
 | 
				
			||||||
zstd = ["zstandard (>=0.18.0)"]
 | 
					zstd = ["zstandard (>=0.18.0)"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "virtualenv"
 | 
				
			||||||
 | 
					version = "20.26.3"
 | 
				
			||||||
 | 
					description = "Virtual Python Environment builder"
 | 
				
			||||||
 | 
					optional = false
 | 
				
			||||||
 | 
					python-versions = ">=3.7"
 | 
				
			||||||
 | 
					files = [
 | 
				
			||||||
 | 
					    {file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"},
 | 
				
			||||||
 | 
					    {file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package.dependencies]
 | 
				
			||||||
 | 
					distlib = ">=0.3.7,<1"
 | 
				
			||||||
 | 
					filelock = ">=3.12.2,<4"
 | 
				
			||||||
 | 
					platformdirs = ">=3.9.1,<5"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package.extras]
 | 
				
			||||||
 | 
					docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
 | 
				
			||||||
 | 
					test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "yarl"
 | 
					name = "yarl"
 | 
				
			||||||
version = "1.9.4"
 | 
					version = "1.9.4"
 | 
				
			||||||
@@ -834,4 +1232,4 @@ multidict = ">=4.0"
 | 
				
			|||||||
[metadata]
 | 
					[metadata]
 | 
				
			||||||
lock-version = "2.0"
 | 
					lock-version = "2.0"
 | 
				
			||||||
python-versions = "^3.11.6"
 | 
					python-versions = "^3.11.6"
 | 
				
			||||||
content-hash = "001611942f2ccb553fc80099924dce739c3cd5febb1438e9bad3e865d1aa8f8b"
 | 
					content-hash = "5b43fa850045f857f8e7b84baa8a9d9b6c9e64758bf8525f4eb772574aafa5ca"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,22 @@ pyyaml = "^6.0.1"
 | 
				
			|||||||
requests = "^2.31.0"
 | 
					requests = "^2.31.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[tool.poetry.group.dev.dependencies]
 | 
				
			||||||
 | 
					flake8 = "^7.1.0"
 | 
				
			||||||
 | 
					black = "^24.4.2"
 | 
				
			||||||
 | 
					isort = "^5.13.2"
 | 
				
			||||||
 | 
					bandit = "^1.7.9"
 | 
				
			||||||
 | 
					pre-commit = "^3.7.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[tool.black]
 | 
				
			||||||
 | 
					line-length = 88
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[tool.isort]
 | 
				
			||||||
 | 
					profile = "black"
 | 
				
			||||||
 | 
					line_length = 88
 | 
				
			||||||
 | 
					multi_line_output = 3
 | 
				
			||||||
 | 
					skip_gitignore = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[build-system]
 | 
					[build-system]
 | 
				
			||||||
requires = ["poetry-core"]
 | 
					requires = ["poetry-core"]
 | 
				
			||||||
build-backend = "poetry.core.masonry.api"
 | 
					build-backend = "poetry.core.masonry.api"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,2 +1,2 @@
 | 
				
			|||||||
import src.service
 | 
					 | 
				
			||||||
import src.core
 | 
					import src.core
 | 
				
			||||||
 | 
					import src.service
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,7 +16,7 @@ def setup_logger():
 | 
				
			|||||||
        filename=log_file,
 | 
					        filename=log_file,
 | 
				
			||||||
        level=logging.INFO,
 | 
					        level=logging.INFO,
 | 
				
			||||||
        format="%(asctime)s %(message)s",
 | 
					        format="%(asctime)s %(message)s",
 | 
				
			||||||
        datefmt="%H:%M:%S"
 | 
					        datefmt="%H:%M:%S",
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,11 @@
 | 
				
			|||||||
 | 
					import asyncio
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from aiogram import Bot, Dispatcher
 | 
				
			||||||
from routers import include_routers
 | 
					from routers import include_routers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from src.core.logger import log, setup_logger
 | 
					from src.core.logger import log, setup_logger
 | 
				
			||||||
from src.modules.standard.config.config import get_telegram_token
 | 
					from src.modules.standard.config.config import get_telegram_token
 | 
				
			||||||
from src.modules.standard.database.db_api import connect_database, create_tables
 | 
					from src.modules.standard.database.db_api import connect_database, create_tables
 | 
				
			||||||
import asyncio
 | 
					 | 
				
			||||||
from aiogram import Bot, Dispatcher
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def main():
 | 
					async def main():
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,10 @@
 | 
				
			|||||||
from aiogram import Dispatcher
 | 
					from aiogram import Dispatcher
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from src.modules.standard.info.routers import router as info_router
 | 
					 | 
				
			||||||
from src.modules.standard.admin.routers import router as admin_router
 | 
					from src.modules.standard.admin.routers import router as admin_router
 | 
				
			||||||
from src.modules.standard.message_processing.message_api import router as process_message
 | 
					from src.modules.standard.info.routers import router as info_router
 | 
				
			||||||
 | 
					from src.modules.standard.message_processing.message_api import (
 | 
				
			||||||
 | 
					    router as process_message,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def include_routers(dp: Dispatcher):
 | 
					async def include_routers(dp: Dispatcher):
 | 
				
			||||||
@@ -13,4 +15,3 @@ async def include_routers(dp: Dispatcher):
 | 
				
			|||||||
    dp.include_router(info_router)
 | 
					    dp.include_router(info_router)
 | 
				
			||||||
    dp.include_router(admin_router)
 | 
					    dp.include_router(admin_router)
 | 
				
			||||||
    dp.include_router(process_message)
 | 
					    dp.include_router(process_message)
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
@@ -1 +0,0 @@
 | 
				
			|||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								src/modules/external/yandexgpt/handlers.py
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								src/modules/external/yandexgpt/handlers.py
									
									
									
									
										vendored
									
									
								
							@@ -1,10 +1,17 @@
 | 
				
			|||||||
 | 
					# flake8: noqa
 | 
				
			||||||
 | 
					import asyncio
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from aiogram import Bot
 | 
					from aiogram import Bot
 | 
				
			||||||
from aiogram.types import Message
 | 
					from aiogram.types import Message
 | 
				
			||||||
from src.modules.external.yandexgpt.yandexgpt import *
 | 
					
 | 
				
			||||||
from src.modules.standard.config.config import get_yandexgpt_token, get_yandexgpt_catalog_id, get_yandexgpt_prompt
 | 
					 | 
				
			||||||
from src.modules.standard.database.db_api import add_message
 | 
					 | 
				
			||||||
from src.core.logger import log
 | 
					from src.core.logger import log
 | 
				
			||||||
import asyncio
 | 
					from src.modules.external.yandexgpt.yandexgpt import *
 | 
				
			||||||
 | 
					from src.modules.standard.config.config import (
 | 
				
			||||||
 | 
					    get_yandexgpt_catalog_id,
 | 
				
			||||||
 | 
					    get_yandexgpt_prompt,
 | 
				
			||||||
 | 
					    get_yandexgpt_token,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					from src.modules.standard.database.db_api import add_message
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def answer_to_message(message: Message, bot: Bot):
 | 
					async def answer_to_message(message: Message, bot: Bot):
 | 
				
			||||||
@@ -14,6 +21,8 @@ async def answer_to_message(message: Message, bot: Bot):
 | 
				
			|||||||
    text = message.text
 | 
					    text = message.text
 | 
				
			||||||
    prompt = get_yandexgpt_prompt()
 | 
					    prompt = get_yandexgpt_prompt()
 | 
				
			||||||
    # response = await yagpt.async_yandexgpt(system_prompt=prompt, input_messages=text)
 | 
					    # response = await yagpt.async_yandexgpt(system_prompt=prompt, input_messages=text)
 | 
				
			||||||
    response = await yagpt.yandexgpt_request(chat_id = message.chat.id, message_id = message.message_id, type = "yandexgpt")
 | 
					    response = await yagpt.yandexgpt_request(
 | 
				
			||||||
 | 
					        chat_id=message.chat.id, message_id=message.message_id, type="yandexgpt"
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    reply = await message.reply(response, parse_mode="Markdown")
 | 
					    reply = await message.reply(response, parse_mode="Markdown")
 | 
				
			||||||
    add_message(reply, message_ai_model="yandexgpt")
 | 
					    add_message(reply, message_ai_model="yandexgpt")
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										7
									
								
								src/modules/external/yandexgpt/routers.py
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								src/modules/external/yandexgpt/routers.py
									
									
									
									
										vendored
									
									
								
							@@ -1,7 +1,10 @@
 | 
				
			|||||||
from aiogram import Router, F
 | 
					# flake8: noqa
 | 
				
			||||||
 | 
					from aiogram import F, Router
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from src.modules.external.yandexgpt.handlers import answer_to_message
 | 
					from src.modules.external.yandexgpt.handlers import answer_to_message
 | 
				
			||||||
 | 
					
 | 
				
			||||||
router = Router()
 | 
					router = Router()
 | 
				
			||||||
# Если сообщение содержит в начале текст "Гномик" или "гномик" или отвечает на сообщение бота, то вызывается функция answer_to_message
 | 
					# Если сообщение содержит в начале текст "Гномик" или "гномик" или отвечает на сообщение бота, то вызывается функция answer_to_message
 | 
				
			||||||
router.message.register(answer_to_message, F.text.startswith("Гномик") | F.text.startswith("гномик"))
 | 
					router.message.register(
 | 
				
			||||||
 | 
					    answer_to_message, F.text.startswith("Гномик") | F.text.startswith("гномик")
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										125
									
								
								src/modules/external/yandexgpt/yandexgpt.py
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										125
									
								
								src/modules/external/yandexgpt/yandexgpt.py
									
									
									
									
										vendored
									
									
								
							@@ -1,11 +1,14 @@
 | 
				
			|||||||
import requests
 | 
					# flake8: noqa
 | 
				
			||||||
import json
 | 
					 | 
				
			||||||
import asyncio
 | 
					import asyncio
 | 
				
			||||||
 | 
					import json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import aiohttp
 | 
					import aiohttp
 | 
				
			||||||
 | 
					import requests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from src.core.logger import log
 | 
					from src.core.logger import log
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from ...standard.database import *
 | 
					 | 
				
			||||||
from ...standard.config.config import *
 | 
					from ...standard.config.config import *
 | 
				
			||||||
 | 
					from ...standard.database import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class YandexGPT:
 | 
					class YandexGPT:
 | 
				
			||||||
@@ -29,11 +32,13 @@ class YandexGPT:
 | 
				
			|||||||
            async with session.post(url, headers=headers, json=prompt) as response:
 | 
					            async with session.post(url, headers=headers, json=prompt) as response:
 | 
				
			||||||
                return await response.json()
 | 
					                return await response.json()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def async_token_check(self, messages, gpt, max_tokens, stream, temperature, del_msg_id=1):
 | 
					    async def async_token_check(
 | 
				
			||||||
 | 
					        self, messages, gpt, max_tokens, stream, temperature, del_msg_id=1
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
        url = "https://llm.api.cloud.yandex.net/foundationModels/v1/tokenizeCompletion"
 | 
					        url = "https://llm.api.cloud.yandex.net/foundationModels/v1/tokenizeCompletion"
 | 
				
			||||||
        headers = {
 | 
					        headers = {
 | 
				
			||||||
            "Content-Type": "application/json",
 | 
					            "Content-Type": "application/json",
 | 
				
			||||||
            "Authorization": f"Api-Key {self.token}"
 | 
					            "Authorization": f"Api-Key {self.token}",
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        answer_token = get_yandexgpt_token_for_answer()
 | 
					        answer_token = get_yandexgpt_token_for_answer()
 | 
				
			||||||
        while True:
 | 
					        while True:
 | 
				
			||||||
@@ -43,11 +48,13 @@ class YandexGPT:
 | 
				
			|||||||
                    "completionOptions": {
 | 
					                    "completionOptions": {
 | 
				
			||||||
                        "stream": stream,
 | 
					                        "stream": stream,
 | 
				
			||||||
                        "temperature": temperature,
 | 
					                        "temperature": temperature,
 | 
				
			||||||
                        "maxTokens": max_tokens
 | 
					                        "maxTokens": max_tokens,
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    "messages": messages
 | 
					                    "messages": messages,
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                response = await self.async_request(url=url, headers=headers, prompt=request)
 | 
					                response = await self.async_request(
 | 
				
			||||||
 | 
					                    url=url, headers=headers, prompt=request
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
            except Exception as e:  # TODO: Переделать обработку ошибок
 | 
					            except Exception as e:  # TODO: Переделать обработку ошибок
 | 
				
			||||||
                # print(e)
 | 
					                # print(e)
 | 
				
			||||||
                await log(f"Error: {e}")
 | 
					                await log(f"Error: {e}")
 | 
				
			||||||
@@ -62,12 +69,19 @@ class YandexGPT:
 | 
				
			|||||||
                    Exception("IndexError: list index out of range")
 | 
					                    Exception("IndexError: list index out of range")
 | 
				
			||||||
        return messages
 | 
					        return messages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def async_yandexgpt_lite(self, system_prompt, input_messages, stream=False, temperature=0.6, max_tokens=8000):
 | 
					    async def async_yandexgpt_lite(
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
 | 
					        system_prompt,
 | 
				
			||||||
 | 
					        input_messages,
 | 
				
			||||||
 | 
					        stream=False,
 | 
				
			||||||
 | 
					        temperature=0.6,
 | 
				
			||||||
 | 
					        max_tokens=8000,
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
        url = "https://llm.api.cloud.yandex.net/foundationModels/v1/completion"
 | 
					        url = "https://llm.api.cloud.yandex.net/foundationModels/v1/completion"
 | 
				
			||||||
        gpt = f"gpt://{self.catalog_id}/yandexgpt-lite/latest"
 | 
					        gpt = f"gpt://{self.catalog_id}/yandexgpt-lite/latest"
 | 
				
			||||||
        headers = {
 | 
					        headers = {
 | 
				
			||||||
            "Content-Type": "application/json",
 | 
					            "Content-Type": "application/json",
 | 
				
			||||||
            "Authorization": f"Api-Key {self.token}"
 | 
					            "Authorization": f"Api-Key {self.token}",
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        messages = [{"role": "system", "text": system_prompt}]
 | 
					        messages = [{"role": "system", "text": system_prompt}]
 | 
				
			||||||
@@ -80,12 +94,12 @@ class YandexGPT:
 | 
				
			|||||||
            "completionOptions": {
 | 
					            "completionOptions": {
 | 
				
			||||||
                "stream": stream,
 | 
					                "stream": stream,
 | 
				
			||||||
                "temperature": temperature,
 | 
					                "temperature": temperature,
 | 
				
			||||||
                "maxTokens": max_tokens
 | 
					                "maxTokens": max_tokens,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "messages": messages
 | 
					            "messages": messages,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        response = requests.post(url, headers=headers, json=prompt).text
 | 
					        response = requests.post(url, headers=headers, json=prompt).text  # nosec
 | 
				
			||||||
        return json.loads(response)["result"]["alternatives"][0]["message"]["text"]
 | 
					        return json.loads(response)["result"]["alternatives"][0]["message"]["text"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def async_yandexgpt(
 | 
					    async def async_yandexgpt(
 | 
				
			||||||
@@ -94,13 +108,13 @@ class YandexGPT:
 | 
				
			|||||||
        input_messages,
 | 
					        input_messages,
 | 
				
			||||||
        stream=False,
 | 
					        stream=False,
 | 
				
			||||||
        temperature=0.6,
 | 
					        temperature=0.6,
 | 
				
			||||||
            max_tokens=get_yandexgpt_token_for_request()
 | 
					        max_tokens=get_yandexgpt_token_for_request(),
 | 
				
			||||||
    ):
 | 
					    ):
 | 
				
			||||||
        url = "https://llm.api.cloud.yandex.net/foundationModels/v1/completion"
 | 
					        url = "https://llm.api.cloud.yandex.net/foundationModels/v1/completion"
 | 
				
			||||||
        gpt = f"gpt://{self.catalog_id}/yandexgpt/latest"
 | 
					        gpt = f"gpt://{self.catalog_id}/yandexgpt/latest"
 | 
				
			||||||
        headers = {
 | 
					        headers = {
 | 
				
			||||||
            "Content-Type": "application/json",
 | 
					            "Content-Type": "application/json",
 | 
				
			||||||
            "Authorization": f"Api-Key {self.token}"
 | 
					            "Authorization": f"Api-Key {self.token}",
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        messages = []
 | 
					        messages = []
 | 
				
			||||||
@@ -108,21 +122,24 @@ class YandexGPT:
 | 
				
			|||||||
        for message in input_messages:
 | 
					        for message in input_messages:
 | 
				
			||||||
            messages.append(message)
 | 
					            messages.append(message)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        messages = await self.async_token_check(messages, gpt, max_tokens, stream, temperature)
 | 
					        messages = await self.async_token_check(
 | 
				
			||||||
 | 
					            messages, gpt, max_tokens, stream, temperature
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        request = {
 | 
					        request = {
 | 
				
			||||||
            "modelUri": gpt,
 | 
					            "modelUri": gpt,
 | 
				
			||||||
            "completionOptions": {
 | 
					            "completionOptions": {
 | 
				
			||||||
                "stream": stream,
 | 
					                "stream": stream,
 | 
				
			||||||
                "temperature": temperature,
 | 
					                "temperature": temperature,
 | 
				
			||||||
                "maxTokens": max_tokens
 | 
					                "maxTokens": max_tokens,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "messages": messages
 | 
					            "messages": messages,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        response = await self.async_request(url=url, headers=headers, prompt=request)
 | 
					        response = await self.async_request(
 | 
				
			||||||
 | 
					            url=url, headers=headers, prompt=request
 | 
				
			||||||
 | 
					        )  # nosec
 | 
				
			||||||
        return response["result"]["alternatives"][0]["message"]["text"]
 | 
					        return response["result"]["alternatives"][0]["message"]["text"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    async def async_yandexgpt_translate(self, input_language, output_language, text):
 | 
					    async def async_yandexgpt_translate(self, input_language, output_language, text):
 | 
				
			||||||
        input_language = self.languages[input_language]
 | 
					        input_language = self.languages[input_language]
 | 
				
			||||||
        output_language = self.languages[output_language]
 | 
					        output_language = self.languages[output_language]
 | 
				
			||||||
@@ -130,7 +147,9 @@ class YandexGPT:
 | 
				
			|||||||
        return await self.async_yandexgpt(
 | 
					        return await self.async_yandexgpt(
 | 
				
			||||||
            f"Переведи на {output_language} сохранив оригинальный смысл текста. Верни только результат:",
 | 
					            f"Переведи на {output_language} сохранив оригинальный смысл текста. Верни только результат:",
 | 
				
			||||||
            [{"role": "user", "text": text}],
 | 
					            [{"role": "user", "text": text}],
 | 
				
			||||||
            stream=False, temperature=0.6, max_tokens=8000
 | 
					            stream=False,
 | 
				
			||||||
 | 
					            temperature=0.6,
 | 
				
			||||||
 | 
					            max_tokens=8000,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def async_yandexgpt_spelling_check(self, input_language, text):
 | 
					    async def async_yandexgpt_spelling_check(self, input_language, text):
 | 
				
			||||||
@@ -140,15 +159,19 @@ class YandexGPT:
 | 
				
			|||||||
            f"Проверьте орфографию и пунктуацию текста на {input_language}. Верни исправленный текст "
 | 
					            f"Проверьте орфографию и пунктуацию текста на {input_language}. Верни исправленный текст "
 | 
				
			||||||
            f"без смысловых искажений:",
 | 
					            f"без смысловых искажений:",
 | 
				
			||||||
            [{"role": "user", "text": text}],
 | 
					            [{"role": "user", "text": text}],
 | 
				
			||||||
            stream=False, temperature=0.6, max_tokens=8000
 | 
					            stream=False,
 | 
				
			||||||
 | 
					            temperature=0.6,
 | 
				
			||||||
 | 
					            max_tokens=8000,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def async_yandexgpt_text_history(self, input_messages, stream=False, temperature=0.6, max_tokens=8000):
 | 
					    async def async_yandexgpt_text_history(
 | 
				
			||||||
 | 
					        self, input_messages, stream=False, temperature=0.6, max_tokens=8000
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
        url = "https://llm.api.cloud.yandex.net/foundationModels/v1/completion"
 | 
					        url = "https://llm.api.cloud.yandex.net/foundationModels/v1/completion"
 | 
				
			||||||
        gpt = f"gpt://{self.catalog_id}/summarization/latest"
 | 
					        gpt = f"gpt://{self.catalog_id}/summarization/latest"
 | 
				
			||||||
        headers = {
 | 
					        headers = {
 | 
				
			||||||
            "Content-Type": "application/json",
 | 
					            "Content-Type": "application/json",
 | 
				
			||||||
            "Authorization": f"Api-Key {self.token}"
 | 
					            "Authorization": f"Api-Key {self.token}",
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        messages = []
 | 
					        messages = []
 | 
				
			||||||
@@ -161,15 +184,17 @@ class YandexGPT:
 | 
				
			|||||||
            "completionOptions": {
 | 
					            "completionOptions": {
 | 
				
			||||||
                "stream": stream,
 | 
					                "stream": stream,
 | 
				
			||||||
                "temperature": temperature,
 | 
					                "temperature": temperature,
 | 
				
			||||||
                "maxTokens": max_tokens
 | 
					                "maxTokens": max_tokens,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "messages": messages
 | 
					            "messages": messages,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        response = requests.post(url, headers=headers, json=prompt).text
 | 
					        response = requests.post(url, headers=headers, json=prompt).text  # nosec
 | 
				
			||||||
        return json.loads(response)["result"]["alternatives"][0]["message"]["text"]
 | 
					        return json.loads(response)["result"]["alternatives"][0]["message"]["text"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def async_yandex_cloud_text_to_speech(self, text, voice, emotion, speed, format, quality):
 | 
					    async def async_yandex_cloud_text_to_speech(
 | 
				
			||||||
 | 
					        self, text, voice, emotion, speed, format, quality
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
        tts = "tts.api.cloud.yandex.net/speech/v1/tts:synthesize"
 | 
					        tts = "tts.api.cloud.yandex.net/speech/v1/tts:synthesize"
 | 
				
			||||||
        # TODO: Сделать функцию TTS
 | 
					        # TODO: Сделать функцию TTS
 | 
				
			||||||
        return 0
 | 
					        return 0
 | 
				
			||||||
@@ -187,14 +212,18 @@ class YandexGPT:
 | 
				
			|||||||
            if db_api.get_message_ai_model(chat_id, message_id) != None:
 | 
					            if db_api.get_message_ai_model(chat_id, message_id) != None:
 | 
				
			||||||
                messages.append({"role": "assistant", "text": message})
 | 
					                messages.append({"role": "assistant", "text": message})
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                sender_name = db_api.get_user_name(db_api.get_message_sender_id(chat_id, message_id))
 | 
					                sender_name = db_api.get_user_name(
 | 
				
			||||||
 | 
					                    db_api.get_message_sender_id(chat_id, message_id)
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
                messages.append({"role": "user", "text": sender_name + ": " + message})
 | 
					                messages.append({"role": "user", "text": sender_name + ": " + message})
 | 
				
			||||||
            message_id = db_api.get_answer_to_message_id(chat_id, message_id)
 | 
					            message_id = db_api.get_answer_to_message_id(chat_id, message_id)
 | 
				
			||||||
            if message_id is None:
 | 
					            if message_id is None:
 | 
				
			||||||
                break
 | 
					                break
 | 
				
			||||||
        return list(reversed(messages))
 | 
					        return list(reversed(messages))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def collecting_messages_for_history(self, start_message_id, end_message_id, chat_id):
 | 
					    async def collecting_messages_for_history(
 | 
				
			||||||
 | 
					        self, start_message_id, end_message_id, chat_id
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
        messages = []
 | 
					        messages = []
 | 
				
			||||||
        # Собираем цепочку сообщений в формате: [{"role": "user", "text": "<Имя_пользователя>: Привет!"},
 | 
					        # Собираем цепочку сообщений в формате: [{"role": "user", "text": "<Имя_пользователя>: Привет!"},
 | 
				
			||||||
        # {"role": "assistant", "text": "Привет!"}]
 | 
					        # {"role": "assistant", "text": "Привет!"}]
 | 
				
			||||||
@@ -203,21 +232,33 @@ class YandexGPT:
 | 
				
			|||||||
            if db_api.get_message_ai_model(chat_id, start_message_id) != None:
 | 
					            if db_api.get_message_ai_model(chat_id, start_message_id) != None:
 | 
				
			||||||
                messages.append({"role": "assistant", "text": message})
 | 
					                messages.append({"role": "assistant", "text": message})
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                sender_name = db_api.get_user_name(db_api.get_message_sender_id(chat_id, start_message_id))
 | 
					                sender_name = db_api.get_user_name(
 | 
				
			||||||
 | 
					                    db_api.get_message_sender_id(chat_id, start_message_id)
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
                messages.append({"role": "user", "text": sender_name + ": " + message})
 | 
					                messages.append({"role": "user", "text": sender_name + ": " + message})
 | 
				
			||||||
            start_message_id -= 1
 | 
					            start_message_id -= 1
 | 
				
			||||||
            if start_message_id <= end_message_id:
 | 
					            if start_message_id <= end_message_id:
 | 
				
			||||||
                break
 | 
					                break
 | 
				
			||||||
        return messages.reverse()
 | 
					        return messages.reverse()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def yandexgpt_request(self, message_id = None, type = "yandexgpt-lite", chat_id = None,
 | 
					    async def yandexgpt_request(
 | 
				
			||||||
                                message_id_end = None, input_language = None, output_language = None, text = None):
 | 
					        self,
 | 
				
			||||||
 | 
					        message_id=None,
 | 
				
			||||||
 | 
					        type="yandexgpt-lite",
 | 
				
			||||||
 | 
					        chat_id=None,
 | 
				
			||||||
 | 
					        message_id_end=None,
 | 
				
			||||||
 | 
					        input_language=None,
 | 
				
			||||||
 | 
					        output_language=None,
 | 
				
			||||||
 | 
					        text=None,
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
        if type == "yandexgpt-lite":
 | 
					        if type == "yandexgpt-lite":
 | 
				
			||||||
            messages = await self.collect_messages(message_id, chat_id)
 | 
					            messages = await self.collect_messages(message_id, chat_id)
 | 
				
			||||||
            return await self.async_yandexgpt_lite(
 | 
					            return await self.async_yandexgpt_lite(
 | 
				
			||||||
                system_prompt=get_yandexgpt_prompt(),
 | 
					                system_prompt=get_yandexgpt_prompt(),
 | 
				
			||||||
                input_messages=messages,
 | 
					                input_messages=messages,
 | 
				
			||||||
                stream=False, temperature=0.6, max_tokens=8000
 | 
					                stream=False,
 | 
				
			||||||
 | 
					                temperature=0.6,
 | 
				
			||||||
 | 
					                max_tokens=8000,
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        elif type == "yandexgpt":
 | 
					        elif type == "yandexgpt":
 | 
				
			||||||
            # print("yandexgpt_request")
 | 
					            # print("yandexgpt_request")
 | 
				
			||||||
@@ -226,24 +267,26 @@ class YandexGPT:
 | 
				
			|||||||
            return await self.async_yandexgpt(
 | 
					            return await self.async_yandexgpt(
 | 
				
			||||||
                system_prompt=get_yandexgpt_prompt(),
 | 
					                system_prompt=get_yandexgpt_prompt(),
 | 
				
			||||||
                input_messages=messages,
 | 
					                input_messages=messages,
 | 
				
			||||||
                stream=False, temperature=0.6, max_tokens=get_yandexgpt_token_for_request()
 | 
					                stream=False,
 | 
				
			||||||
 | 
					                temperature=0.6,
 | 
				
			||||||
 | 
					                max_tokens=get_yandexgpt_token_for_request(),
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        elif type == "yandexgpt-translate":
 | 
					        elif type == "yandexgpt-translate":
 | 
				
			||||||
            return await self.async_yandexgpt_translate(
 | 
					            return await self.async_yandexgpt_translate(
 | 
				
			||||||
                input_language,
 | 
					                input_language,
 | 
				
			||||||
                output_language,
 | 
					                output_language,
 | 
				
			||||||
                text=db_api.get_message_text(chat_id, message_id)
 | 
					                text=db_api.get_message_text(chat_id, message_id),
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        elif type == "yandexgpt-spelling-check":
 | 
					        elif type == "yandexgpt-spelling-check":
 | 
				
			||||||
            return await self.async_yandexgpt_spelling_check(
 | 
					            return await self.async_yandexgpt_spelling_check(
 | 
				
			||||||
                input_language,
 | 
					                input_language, text=db_api.get_message_text(chat_id, message_id)
 | 
				
			||||||
                text=db_api.get_message_text(chat_id, message_id)
 | 
					 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        elif type == "yandexgpt-text-history":
 | 
					        elif type == "yandexgpt-text-history":
 | 
				
			||||||
            messages = await self.collect_messages_for_history(message_id, message_id_end, chat_id)
 | 
					            messages = await self.collect_messages_for_history(
 | 
				
			||||||
 | 
					                message_id, message_id_end, chat_id
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
            return await self.async_yandexgpt_text_history(
 | 
					            return await self.async_yandexgpt_text_history(
 | 
				
			||||||
                messages=messages,
 | 
					                messages=messages, stream=False, temperature=0.6, max_tokens=8000
 | 
				
			||||||
                stream=False, temperature=0.6, max_tokens=8000
 | 
					 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            return "Ошибка: Неизвестный тип запроса | Error: Unknown request type"
 | 
					            return "Ошибка: Неизвестный тип запроса | Error: Unknown request type"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +1,26 @@
 | 
				
			|||||||
 | 
					# flake8: noqa
 | 
				
			||||||
 | 
					import time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from aiogram import Bot
 | 
					from aiogram import Bot
 | 
				
			||||||
from aiogram.types import Message
 | 
					from aiogram.types import Message
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from src.modules.standard.config.config import get_default_chat_tag
 | 
					from src.modules.standard.config.config import get_default_chat_tag
 | 
				
			||||||
import time
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def delete_message(message: Message, bot: Bot):
 | 
					async def delete_message(message: Message, bot: Bot):
 | 
				
			||||||
    reply_message_id = message.reply_to_message.message_id
 | 
					    reply_message_id = message.reply_to_message.message_id
 | 
				
			||||||
    await bot.delete_message(message.chat.id, reply_message_id)
 | 
					    await bot.delete_message(message.chat.id, reply_message_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def error_access(message: Message, bot: Bot):
 | 
					async def error_access(message: Message, bot: Bot):
 | 
				
			||||||
    await message.reply("Вы не админ/модератор")
 | 
					    await message.reply("Вы не админ/модератор")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def get_chat_id(message: Message, bot: Bot):
 | 
					async def get_chat_id(message: Message, bot: Bot):
 | 
				
			||||||
    await message.reply(f"ID данного чата: `{message.chat.id}`", parse_mode="MarkdownV2")
 | 
					    await message.reply(
 | 
				
			||||||
 | 
					        f"ID данного чата: `{message.chat.id}`", parse_mode="MarkdownV2"
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def chat_not_in_approve_list(message: Message, bot: Bot):
 | 
					async def chat_not_in_approve_list(message: Message, bot: Bot):
 | 
				
			||||||
    await message.reply(
 | 
					    await message.reply(
 | 
				
			||||||
@@ -22,6 +30,7 @@ async def chat_not_in_approve_list(message: Message, bot: Bot):
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
    await get_chat_id(message, bot)
 | 
					    await get_chat_id(message, bot)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def mute_user(chat_id: int, user_id: int, time: int, bot: Bot):
 | 
					async def mute_user(chat_id: int, user_id: int, time: int, bot: Bot):
 | 
				
			||||||
    # *, can_send_messages: bool | None = None, can_send_audios: bool | None = None, can_send_documents: bool | None = None, can_send_photos: bool | None = None, can_send_videos: bool | None = None, can_send_video_notes: bool | None = None, can_send_voice_notes: bool | None = None, can_send_polls: bool | None = None, can_send_other_messages: bool | None = None, can_add_web_page_previews: bool | None = None, can_change_info: bool | None = None, can_invite_users: bool | None = None, can_pin_messages: bool | None = None, can_manage_topics: bool | None = None, **extra_data: Any)
 | 
					    # *, can_send_messages: bool | None = None, can_send_audios: bool | None = None, can_send_documents: bool | None = None, can_send_photos: bool | None = None, can_send_videos: bool | None = None, can_send_video_notes: bool | None = None, can_send_voice_notes: bool | None = None, can_send_polls: bool | None = None, can_send_other_messages: bool | None = None, can_add_web_page_previews: bool | None = None, can_change_info: bool | None = None, can_invite_users: bool | None = None, can_pin_messages: bool | None = None, can_manage_topics: bool | None = None, **extra_data: Any)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -39,8 +48,9 @@ async def mute_user(chat_id: int, user_id: int, time: int, bot: Bot):
 | 
				
			|||||||
        "can_change_info": False,
 | 
					        "can_change_info": False,
 | 
				
			||||||
        "can_invite_users": False,
 | 
					        "can_invite_users": False,
 | 
				
			||||||
        "can_pin_messages": False,
 | 
					        "can_pin_messages": False,
 | 
				
			||||||
        "can_manage_topics": False
 | 
					        "can_manage_topics": False,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    end_time = time + int(time.time())
 | 
					    end_time = time + int(time.time())
 | 
				
			||||||
    await bot.restrict_chat_member(chat_id, user_id, until_date=end_time, **mutePermissions)
 | 
					    await bot.restrict_chat_member(
 | 
				
			||||||
 | 
					        chat_id, user_id, until_date=end_time, **mutePermissions
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,15 +1,24 @@
 | 
				
			|||||||
from aiogram import Router, F
 | 
					# flake8: noqa
 | 
				
			||||||
 | 
					from aiogram import F, Router
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from src.modules.standard.admin.handlers import delete_message, error_access, get_chat_id, chat_not_in_approve_list
 | 
					from src.modules.standard.admin.handlers import (
 | 
				
			||||||
from src.modules.standard.filters.filters import ChatModerOrAdminFilter, ChatNotInApproveFilter
 | 
					    chat_not_in_approve_list,
 | 
				
			||||||
 | 
					    delete_message,
 | 
				
			||||||
 | 
					    error_access,
 | 
				
			||||||
 | 
					    get_chat_id,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					from src.modules.standard.filters.filters import (
 | 
				
			||||||
 | 
					    ChatModerOrAdminFilter,
 | 
				
			||||||
 | 
					    ChatNotInApproveFilter,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
router = Router()
 | 
					router = Router()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Если сообщение содержит какой либо текст и выполняется фильтр ChatNotInApproveFilter, то вызывается функция chat_not_in_approve_list
 | 
					# Если сообщение содержит какой либо текст и выполняется фильтр ChatNotInApproveFilter, то вызывается функция chat_not_in_approve_list
 | 
				
			||||||
router.message.register(chat_not_in_approve_list, ChatNotInApproveFilter(), F.text)
 | 
					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(), F.text == "/chatID")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
router.message.register(delete_message, ChatModerOrAdminFilter(), F.text == '/rm')
 | 
					router.message.register(delete_message, ChatModerOrAdminFilter(), F.text == "/rm")
 | 
				
			||||||
router.message.register(error_access, F.text == '/rm')
 | 
					router.message.register(error_access, F.text == "/rm")
 | 
				
			||||||
router.message.register(error_access, F.text == '/chatID')
 | 
					router.message.register(error_access, F.text == "/chatID")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,7 @@
 | 
				
			|||||||
 | 
					# flake8: noqa
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import yaml
 | 
					import yaml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from ....service import paths
 | 
					from ....service import paths
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -9,52 +12,64 @@ def get_config(is_test: bool = False) -> dict:
 | 
				
			|||||||
        path = paths.core
 | 
					        path = paths.core
 | 
				
			||||||
    path = f"{path}/config.yaml"
 | 
					    path = f"{path}/config.yaml"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with open(path, 'r') as file:
 | 
					    with open(path, "r") as file:
 | 
				
			||||||
        return yaml.full_load(file)
 | 
					        return yaml.full_load(file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config = get_config()
 | 
					config = get_config()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_telegram_token() -> str:
 | 
					def get_telegram_token() -> str:
 | 
				
			||||||
    return config["TELEGRAM"]["TOKEN"]
 | 
					    return config["TELEGRAM"]["TOKEN"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_telegram_check_bot() -> bool:
 | 
					def get_telegram_check_bot() -> bool:
 | 
				
			||||||
    return config["TELEGRAM"]["CHECK_BOT"]
 | 
					    return config["TELEGRAM"]["CHECK_BOT"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_aproved_chat_id() -> list:
 | 
					def get_aproved_chat_id() -> list:
 | 
				
			||||||
    # Возваращем сплитованный список id чатов в формате int
 | 
					    # Возваращем сплитованный список id чатов в формате int
 | 
				
			||||||
    return [int(chat_id) for chat_id in config["TELEGRAM"]["APPROVED_CHAT_ID"].split(" | ")]
 | 
					    return [
 | 
				
			||||||
 | 
					        int(chat_id) for chat_id in config["TELEGRAM"]["APPROVED_CHAT_ID"].split(" | ")
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_user_role_name(role_number) -> dict:
 | 
					def get_user_role_name(role_number) -> dict:
 | 
				
			||||||
    # Возвращаем название роли пользвателя по номеру роли, если такой роли нет, возвращаем неизвестно
 | 
					    # Возвращаем название роли пользвателя по номеру роли, если такой роли нет, возвращаем неизвестно
 | 
				
			||||||
    return config["ROLES"].get(role_number, "Неизвестно")
 | 
					    return config["ROLES"].get(role_number, "Неизвестно")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_default_chat_tag() -> str:
 | 
					def get_default_chat_tag() -> str:
 | 
				
			||||||
    return config["TELEGRAM"]["DEFAULT_CHAT_TAG"]
 | 
					    return config["TELEGRAM"]["DEFAULT_CHAT_TAG"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_yandexgpt_token() -> str:
 | 
					def get_yandexgpt_token() -> str:
 | 
				
			||||||
    return config["YANDEXGPT"]["TOKEN"]
 | 
					    return config["YANDEXGPT"]["TOKEN"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_yandexgpt_catalog_id() -> str:
 | 
					def get_yandexgpt_catalog_id() -> str:
 | 
				
			||||||
    return config["YANDEXGPT"]["CATALOGID"]
 | 
					    return config["YANDEXGPT"]["CATALOGID"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_yandexgpt_prompt() -> str:
 | 
					def get_yandexgpt_prompt() -> str:
 | 
				
			||||||
    return config["YANDEXGPT"]["PROMPT"]
 | 
					    return config["YANDEXGPT"]["PROMPT"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_yandexgpt_start_words() -> list:
 | 
					def get_yandexgpt_start_words() -> list:
 | 
				
			||||||
    return config["YANDEXGPT"]["STARTWORD"].split(" | ")
 | 
					    return config["YANDEXGPT"]["STARTWORD"].split(" | ")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_yandexgpt_in_words() -> list:
 | 
					def get_yandexgpt_in_words() -> list:
 | 
				
			||||||
    return config["YANDEXGPT"]["INWORD"].split(" | ")
 | 
					    return config["YANDEXGPT"]["INWORD"].split(" | ")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_yandexgpt_token_for_request() -> int:
 | 
					def get_yandexgpt_token_for_request() -> int:
 | 
				
			||||||
    return config["YANDEXGPT"]["TOKEN_FOR_REQUEST"]
 | 
					    return config["YANDEXGPT"]["TOKEN_FOR_REQUEST"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_yandexgpt_token_for_answer() -> int:
 | 
					def get_yandexgpt_token_for_answer() -> int:
 | 
				
			||||||
    return config["YANDEXGPT"]["TOKEN_FOR_ANSWER"]
 | 
					    return config["YANDEXGPT"]["TOKEN_FOR_ANSWER"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_access_rights() -> dict:
 | 
					def get_access_rights() -> dict:
 | 
				
			||||||
    return get_config()["ACCESS_RIGHTS"]
 | 
					    return get_config()["ACCESS_RIGHTS"]
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
from src.modules.standard.config.config import get_config
 | 
					 | 
				
			||||||
import unittest
 | 
					import unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from src.modules.standard.config.config import get_config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
yaml_load = get_config(is_test=True)
 | 
					yaml_load = get_config(is_test=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -18,20 +19,27 @@ class TestConfig(unittest.TestCase):
 | 
				
			|||||||
    def test_yaml_keys_existence(self):
 | 
					    def test_yaml_keys_existence(self):
 | 
				
			||||||
        self.assertTrue(all(key in yaml_load for key in ["TELEGRAM", "ROLES"]))
 | 
					        self.assertTrue(all(key in yaml_load for key in ["TELEGRAM", "ROLES"]))
 | 
				
			||||||
        self.assertIn("TOKEN", yaml_load["TELEGRAM"])
 | 
					        self.assertIn("TOKEN", yaml_load["TELEGRAM"])
 | 
				
			||||||
        self.assertTrue(all(role in yaml_load["ROLES"] for role in ["ADMIN", "MODERATOR", "USER"]))
 | 
					        self.assertTrue(
 | 
				
			||||||
 | 
					            all(role in yaml_load["ROLES"] for role in ["ADMIN", "MODERATOR", "USER"])
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_yaml_yaml_load_types(self):
 | 
					    def test_yaml_yaml_load_types(self):
 | 
				
			||||||
        self.assertIsInstance(yaml_load["TELEGRAM"]["TOKEN"], str)
 | 
					        self.assertIsInstance(yaml_load["TELEGRAM"]["TOKEN"], str)
 | 
				
			||||||
        self.assertTrue(all(isinstance(yaml_load["ROLES"][role], int) for role in ["ADMIN", "MODERATOR", "USER"]))
 | 
					        self.assertTrue(
 | 
				
			||||||
 | 
					            all(
 | 
				
			||||||
 | 
					                isinstance(yaml_load["ROLES"][role], int)
 | 
				
			||||||
 | 
					                for role in ["ADMIN", "MODERATOR", "USER"]
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_yaml_values(self):
 | 
					    def test_yaml_values(self):
 | 
				
			||||||
        expected_token = 'xxxxxxxxxxxxxxxxxxxx'
 | 
					        expected_token = "xxxxxxxxxxxxxxxxxxxx"  # nosec
 | 
				
			||||||
        expected_role_values = {'ADMIN': 0, 'MODERATOR': 1, 'USER': 2, 'BOT': 3}
 | 
					        expected_role_values = {"ADMIN": 0, "MODERATOR": 1, "USER": 2, "BOT": 3}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertEqual(yaml_load["TELEGRAM"]["TOKEN"], expected_token)
 | 
					        self.assertEqual(yaml_load["TELEGRAM"]["TOKEN"], expected_token)
 | 
				
			||||||
        for role, value in expected_role_values.items():
 | 
					        for role, value in expected_role_values.items():
 | 
				
			||||||
            self.assertEqual(yaml_load["ROLES"][role], value)
 | 
					            self.assertEqual(yaml_load["ROLES"][role], value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == "__main__":
 | 
				
			||||||
    unittest.main()
 | 
					    unittest.main()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,14 @@
 | 
				
			|||||||
from .models.chats import Chats
 | 
					 | 
				
			||||||
from .models.messages import Messages
 | 
					 | 
				
			||||||
from .models.users import Users
 | 
					 | 
				
			||||||
from .models.user_stats import UserStats
 | 
					 | 
				
			||||||
from .models.chat_stats import ChatStats
 | 
					 | 
				
			||||||
from ....service import paths
 | 
					 | 
				
			||||||
from ..exceptions.module_exceptions import MissingModuleName, NotExpectedModuleName
 | 
					 | 
				
			||||||
import peewee as pw
 | 
					import peewee as pw
 | 
				
			||||||
from aiogram.types import Message
 | 
					from aiogram.types import Message
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ....service import paths
 | 
				
			||||||
 | 
					from ..exceptions.module_exceptions import MissingModuleName, NotExpectedModuleName
 | 
				
			||||||
 | 
					from .models.chat_stats import ChatStats
 | 
				
			||||||
 | 
					from .models.chats import Chats
 | 
				
			||||||
 | 
					from .models.messages import Messages
 | 
				
			||||||
 | 
					from .models.user_stats import UserStats
 | 
				
			||||||
 | 
					from .models.users import Users
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def connect_database(is_test: bool = False, module: str | None = None):
 | 
					def connect_database(is_test: bool = False, module: str | None = None):
 | 
				
			||||||
    if is_test:
 | 
					    if is_test:
 | 
				
			||||||
@@ -37,11 +38,14 @@ def create_tables(db: pw.SqliteDatabase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def add_chat(chat_id, chat_name, chat_type=10, chat_stats=0):
 | 
					def add_chat(chat_id, chat_name, chat_type=10, chat_stats=0):
 | 
				
			||||||
    chat, created = Chats.get_or_create(id=chat_id, defaults={
 | 
					    chat, created = Chats.get_or_create(
 | 
				
			||||||
        'chat_name': chat_name,
 | 
					        id=chat_id,
 | 
				
			||||||
        'chat_type': chat_type,
 | 
					        defaults={
 | 
				
			||||||
        'chat_all_stat': chat_stats,
 | 
					            "chat_name": chat_name,
 | 
				
			||||||
    })
 | 
					            "chat_type": chat_type,
 | 
				
			||||||
 | 
					            "chat_all_stat": chat_stats,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    if not created:
 | 
					    if not created:
 | 
				
			||||||
        # Обновить существующий чат, если он уже существует
 | 
					        # Обновить существующий чат, если он уже существует
 | 
				
			||||||
        chat.chat_name = chat_name
 | 
					        chat.chat_name = chat_name
 | 
				
			||||||
@@ -50,19 +54,30 @@ def add_chat(chat_id, chat_name, chat_type=10, chat_stats=0):
 | 
				
			|||||||
        chat.save()
 | 
					        chat.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def add_user(user_id, user_first_name, user_last_name=None, user_tag=None, user_role=0, user_stats=0, user_rep=0):
 | 
					def add_user(
 | 
				
			||||||
 | 
					    user_id,
 | 
				
			||||||
 | 
					    user_first_name,
 | 
				
			||||||
 | 
					    user_last_name=None,
 | 
				
			||||||
 | 
					    user_tag=None,
 | 
				
			||||||
 | 
					    user_role=0,
 | 
				
			||||||
 | 
					    user_stats=0,
 | 
				
			||||||
 | 
					    user_rep=0,
 | 
				
			||||||
 | 
					):
 | 
				
			||||||
    if user_last_name is None:
 | 
					    if user_last_name is None:
 | 
				
			||||||
        user_name = user_first_name
 | 
					        user_name = user_first_name
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        user_name = user_first_name + " " + user_last_name
 | 
					        user_name = user_first_name + " " + user_last_name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    user, created = Users.get_or_create(id=user_id, defaults={
 | 
					    user, created = Users.get_or_create(
 | 
				
			||||||
        'user_tag': user_tag,
 | 
					        id=user_id,
 | 
				
			||||||
        'user_name': user_name,
 | 
					        defaults={
 | 
				
			||||||
        'user_role': user_role,
 | 
					            "user_tag": user_tag,
 | 
				
			||||||
        'user_stats': user_stats,
 | 
					            "user_name": user_name,
 | 
				
			||||||
        'user_rep': user_rep
 | 
					            "user_role": user_role,
 | 
				
			||||||
    })
 | 
					            "user_stats": user_stats,
 | 
				
			||||||
 | 
					            "user_rep": user_rep,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    if not created:
 | 
					    if not created:
 | 
				
			||||||
        # Обновить существующего пользователя, если он уже существует
 | 
					        # Обновить существующего пользователя, если он уже существует
 | 
				
			||||||
        user.user_tag = user_tag
 | 
					        user.user_tag = user_tag
 | 
				
			||||||
@@ -84,26 +99,20 @@ def add_message(message: Message, message_ai_model=None):
 | 
				
			|||||||
        message_sender_id=message.from_user.id,
 | 
					        message_sender_id=message.from_user.id,
 | 
				
			||||||
        answer_to_message_id=answer_to_message_id,
 | 
					        answer_to_message_id=answer_to_message_id,
 | 
				
			||||||
        message_ai_model=message_ai_model,
 | 
					        message_ai_model=message_ai_model,
 | 
				
			||||||
        message_text=message.text
 | 
					        message_text=message.text,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def add_chat_stats(chat_id, date, messages_count):
 | 
					def add_chat_stats(chat_id, date, messages_count):
 | 
				
			||||||
    ChatStats.create(
 | 
					    ChatStats.create(chat_id=chat_id, date=date, messages_count=messages_count)
 | 
				
			||||||
        chat_id=chat_id,
 | 
					 | 
				
			||||||
        date=date,
 | 
					 | 
				
			||||||
        messages_count=messages_count
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def add_user_stats(chat_id, user_id, date, messages_count):
 | 
					def add_user_stats(chat_id, user_id, date, messages_count):
 | 
				
			||||||
    UserStats.create(
 | 
					    UserStats.create(
 | 
				
			||||||
        chat_id=chat_id,
 | 
					        chat_id=chat_id, user_id=user_id, date=date, messages_count=messages_count
 | 
				
			||||||
        user_id=user_id,
 | 
					 | 
				
			||||||
        date=date,
 | 
					 | 
				
			||||||
        messages_count=messages_count
 | 
					 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Работа с таблицей чатов
 | 
					# Работа с таблицей чатов
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -125,6 +134,7 @@ def get_chat_all_stat(chat_id):
 | 
				
			|||||||
    chat = Chats.get_or_none(Chats.id == chat_id)
 | 
					    chat = Chats.get_or_none(Chats.id == chat_id)
 | 
				
			||||||
    return chat.chat_all_stat if chat else None
 | 
					    return chat.chat_all_stat if chat else None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Работа с таблицей пользователей
 | 
					# Работа с таблицей пользователей
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -136,6 +146,7 @@ def get_user_tag(user_id):
 | 
				
			|||||||
    user = Users.get_or_none(Users.id == user_id)
 | 
					    user = Users.get_or_none(Users.id == user_id)
 | 
				
			||||||
    return user.user_tag if user else None
 | 
					    return user.user_tag if user else None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_user_id(user_tag):
 | 
					def get_user_id(user_tag):
 | 
				
			||||||
    user = Users.get_or_none(Users.user_tag == user_tag)
 | 
					    user = Users.get_or_none(Users.user_tag == user_tag)
 | 
				
			||||||
    return user.id if user else None
 | 
					    return user.id if user else None
 | 
				
			||||||
@@ -179,32 +190,44 @@ def change_user_role(user_id, new_user_role):
 | 
				
			|||||||
    query = Users.update(user_role=new_user_role).where(Users.id == user_id)
 | 
					    query = Users.update(user_role=new_user_role).where(Users.id == user_id)
 | 
				
			||||||
    query.execute()
 | 
					    query.execute()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Работа с таблицей сообщений
 | 
					# Работа с таблицей сообщений
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_message(message_chat_id, message_id):
 | 
					def get_message(message_chat_id, message_id):
 | 
				
			||||||
    return Messages.get_or_none(Messages.message_chat_id == message_chat_id, Messages.message_id == message_id)
 | 
					    return Messages.get_or_none(
 | 
				
			||||||
 | 
					        Messages.message_chat_id == message_chat_id, Messages.message_id == message_id
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_message_sender_id(message_chat_id, message_id):
 | 
					def get_message_sender_id(message_chat_id, message_id):
 | 
				
			||||||
    message = Messages.get_or_none(Messages.message_chat_id == message_chat_id, Messages.message_id == message_id)
 | 
					    message = Messages.get_or_none(
 | 
				
			||||||
 | 
					        Messages.message_chat_id == message_chat_id, Messages.message_id == message_id
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    return message.message_sender_id if message else None
 | 
					    return message.message_sender_id if message else None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_message_text(message_chat_id, message_id):
 | 
					def get_message_text(message_chat_id, message_id):
 | 
				
			||||||
    message = Messages.get_or_none(Messages.message_chat_id == message_chat_id, Messages.message_id == message_id)
 | 
					    message = Messages.get_or_none(
 | 
				
			||||||
 | 
					        Messages.message_chat_id == message_chat_id, Messages.message_id == message_id
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    return message.message_text if message else None
 | 
					    return message.message_text if message else None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_message_ai_model(message_chat_id, message_id):
 | 
					def get_message_ai_model(message_chat_id, message_id):
 | 
				
			||||||
    message = Messages.get_or_none(Messages.message_chat_id == message_chat_id, Messages.message_id == message_id)
 | 
					    message = Messages.get_or_none(
 | 
				
			||||||
 | 
					        Messages.message_chat_id == message_chat_id, Messages.message_id == message_id
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    return message.message_ai_model if message else None
 | 
					    return message.message_ai_model if message else None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_answer_to_message_id(message_chat_id, message_id):
 | 
					def get_answer_to_message_id(message_chat_id, message_id):
 | 
				
			||||||
    message = Messages.get_or_none(Messages.message_chat_id == message_chat_id, Messages.message_id == message_id)
 | 
					    message = Messages.get_or_none(
 | 
				
			||||||
 | 
					        Messages.message_chat_id == message_chat_id, Messages.message_id == message_id
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    return message.answer_to_message_id if message else None
 | 
					    return message.answer_to_message_id if message else None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Работа с таблицей статистики чатов
 | 
					# Работа с таблицей статистики чатов
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -214,6 +237,7 @@ def get_chat_stats(chat_id):
 | 
				
			|||||||
        chat_stats[chat_stat.date] = chat_stat.messages_count
 | 
					        chat_stats[chat_stat.date] = chat_stat.messages_count
 | 
				
			||||||
    return chat_stats
 | 
					    return chat_stats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Работа с таблицей статистики пользователей
 | 
					# Работа с таблицей статистики пользователей
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -223,26 +247,28 @@ def get_user_stats(user_id):
 | 
				
			|||||||
        user_stats[user_stat.date] = user_stat.messages_count
 | 
					        user_stats[user_stat.date] = user_stat.messages_count
 | 
				
			||||||
    return user_stats
 | 
					    return user_stats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Функции обновления
 | 
					# Функции обновления
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def update_chat_all_stat(chat_id):
 | 
					def update_chat_all_stat(chat_id):
 | 
				
			||||||
    query = Chats.update(chat_all_stat=Chats.chat_all_stat + 1).where(Chats.id == chat_id)
 | 
					    query = Chats.update(chat_all_stat=Chats.chat_all_stat + 1).where(
 | 
				
			||||||
 | 
					        Chats.id == chat_id
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    query.execute()
 | 
					    query.execute()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def update_chat_stats(chat_id, date):
 | 
					def update_chat_stats(chat_id, date):
 | 
				
			||||||
    chat_stats = ChatStats.get_or_none(ChatStats.chat_id == chat_id, ChatStats.date == date)
 | 
					    chat_stats = ChatStats.get_or_none(
 | 
				
			||||||
 | 
					        ChatStats.chat_id == chat_id, ChatStats.date == date
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    if chat_stats:
 | 
					    if chat_stats:
 | 
				
			||||||
        query = ChatStats.update(messages_count=ChatStats.messages_count + 1).where(ChatStats.chat_id == chat_id,
 | 
					        query = ChatStats.update(messages_count=ChatStats.messages_count + 1).where(
 | 
				
			||||||
                                                                                    ChatStats.date == date)
 | 
					            ChatStats.chat_id == chat_id, ChatStats.date == date
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        query.execute()
 | 
					        query.execute()
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        ChatStats.create(
 | 
					        ChatStats.create(chat_id=chat_id, date=date, messages_count=1)
 | 
				
			||||||
            chat_id=chat_id,
 | 
					 | 
				
			||||||
            date=date,
 | 
					 | 
				
			||||||
            messages_count=1
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def update_user_all_stat(user_id):
 | 
					def update_user_all_stat(user_id):
 | 
				
			||||||
@@ -251,10 +277,7 @@ def update_user_all_stat(user_id):
 | 
				
			|||||||
        query = Users.update(user_stats=Users.user_stats + 1).where(Users.id == user_id)
 | 
					        query = Users.update(user_stats=Users.user_stats + 1).where(Users.id == user_id)
 | 
				
			||||||
        query.execute()
 | 
					        query.execute()
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        Users.create(
 | 
					        Users.create(id=user_id, user_stats=1)
 | 
				
			||||||
            id=user_id,
 | 
					 | 
				
			||||||
            user_stats=1
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def update_user_rep(user_id):
 | 
					def update_user_rep(user_id):
 | 
				
			||||||
@@ -263,24 +286,21 @@ def update_user_rep(user_id):
 | 
				
			|||||||
        query = Users.update(user_rep=Users.user_rep + 1).where(Users.id == user_id)
 | 
					        query = Users.update(user_rep=Users.user_rep + 1).where(Users.id == user_id)
 | 
				
			||||||
        query.execute()
 | 
					        query.execute()
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        Users.create(
 | 
					        Users.create(id=user_id, user_rep=1)
 | 
				
			||||||
            id=user_id,
 | 
					 | 
				
			||||||
            user_rep=1
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def update_user_stats(chat_id, user_id, date):
 | 
					def update_user_stats(chat_id, user_id, date):
 | 
				
			||||||
    user_stats = UserStats.get_or_none(UserStats.chat_id == chat_id, UserStats.user_id == user_id,
 | 
					    user_stats = UserStats.get_or_none(
 | 
				
			||||||
                                       UserStats.date == date)
 | 
					        UserStats.chat_id == chat_id,
 | 
				
			||||||
    if user_stats:
 | 
					 | 
				
			||||||
        query = UserStats.update(messages_count=UserStats.messages_count + 1).where(UserStats.chat_id == chat_id,
 | 
					 | 
				
			||||||
        UserStats.user_id == user_id,
 | 
					        UserStats.user_id == user_id,
 | 
				
			||||||
                                                                                    UserStats.date == date)
 | 
					        UserStats.date == date,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    if user_stats:
 | 
				
			||||||
 | 
					        query = UserStats.update(messages_count=UserStats.messages_count + 1).where(
 | 
				
			||||||
 | 
					            UserStats.chat_id == chat_id,
 | 
				
			||||||
 | 
					            UserStats.user_id == user_id,
 | 
				
			||||||
 | 
					            UserStats.date == date,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        query.execute()
 | 
					        query.execute()
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        UserStats.create(
 | 
					        UserStats.create(chat_id=chat_id, user_id=user_id, date=date, messages_count=1)
 | 
				
			||||||
            chat_id=chat_id,
 | 
					 | 
				
			||||||
            user_id=user_id,
 | 
					 | 
				
			||||||
            date=date,
 | 
					 | 
				
			||||||
            messages_count=1
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +0,0 @@
 | 
				
			|||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,8 +2,8 @@ import peewee as pw
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ChatStats(pw.Model):
 | 
					class ChatStats(pw.Model):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta: ...
 | 
				
			||||||
        ...
 | 
					
 | 
				
			||||||
    chat_id = pw.IntegerField(null=False)
 | 
					    chat_id = pw.IntegerField(null=False)
 | 
				
			||||||
    date = pw.DateField(null=False)
 | 
					    date = pw.DateField(null=False)
 | 
				
			||||||
    messages_count = pw.IntegerField(null=False, default=0)
 | 
					    messages_count = pw.IntegerField(null=False, default=0)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,8 +2,8 @@ import peewee as pw
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Chats(pw.Model):
 | 
					class Chats(pw.Model):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta: ...
 | 
				
			||||||
        ...
 | 
					
 | 
				
			||||||
    chat_name = pw.CharField(null=False)
 | 
					    chat_name = pw.CharField(null=False)
 | 
				
			||||||
    chat_type = pw.IntegerField(null=False, default=10)
 | 
					    chat_type = pw.IntegerField(null=False, default=10)
 | 
				
			||||||
    chat_all_stat = pw.IntegerField(null=False)
 | 
					    chat_all_stat = pw.IntegerField(null=False)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,12 +2,11 @@ import peewee as pw
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Messages(pw.Model):
 | 
					class Messages(pw.Model):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta: ...
 | 
				
			||||||
        ...
 | 
					
 | 
				
			||||||
    message_chat_id = pw.IntegerField(null=False)
 | 
					    message_chat_id = pw.IntegerField(null=False)
 | 
				
			||||||
    message_id = pw.IntegerField(null=False)
 | 
					    message_id = pw.IntegerField(null=False)
 | 
				
			||||||
    message_sender_id = pw.IntegerField(null=False)
 | 
					    message_sender_id = pw.IntegerField(null=False)
 | 
				
			||||||
    answer_to_message_id = pw.IntegerField(null=True)
 | 
					    answer_to_message_id = pw.IntegerField(null=True)
 | 
				
			||||||
    message_ai_model = pw.TextField(null=True)
 | 
					    message_ai_model = pw.TextField(null=True)
 | 
				
			||||||
    message_text = pw.TextField(null=False)
 | 
					    message_text = pw.TextField(null=False)
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,8 +2,8 @@ import peewee as pw
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UserStats(pw.Model):
 | 
					class UserStats(pw.Model):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta: ...
 | 
				
			||||||
        ...
 | 
					
 | 
				
			||||||
    chat_id = pw.IntegerField(null=False)
 | 
					    chat_id = pw.IntegerField(null=False)
 | 
				
			||||||
    user_id = pw.IntegerField(null=False)
 | 
					    user_id = pw.IntegerField(null=False)
 | 
				
			||||||
    date = pw.DateField(null=False)
 | 
					    date = pw.DateField(null=False)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,8 +2,8 @@ import peewee as pw
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Users(pw.Model):
 | 
					class Users(pw.Model):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta: ...
 | 
				
			||||||
        ...
 | 
					
 | 
				
			||||||
    user_tag = pw.CharField(null=True)
 | 
					    user_tag = pw.CharField(null=True)
 | 
				
			||||||
    user_name = pw.CharField(null=False)  # до 255 символов
 | 
					    user_name = pw.CharField(null=False)  # до 255 символов
 | 
				
			||||||
    user_role = pw.IntegerField(null=True, default=3)
 | 
					    user_role = pw.IntegerField(null=True, default=3)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,10 @@
 | 
				
			|||||||
import unittest
 | 
					# flake8: noqa
 | 
				
			||||||
import os
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from ..db_api import *
 | 
					 | 
				
			||||||
from ...exceptions.module_exceptions import MissingModuleName, NotExpectedModuleName
 | 
					from ...exceptions.module_exceptions import MissingModuleName, NotExpectedModuleName
 | 
				
			||||||
 | 
					from ..db_api import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestDatabaseAPI(unittest.TestCase):
 | 
					class TestDatabaseAPI(unittest.TestCase):
 | 
				
			||||||
@@ -13,6 +15,7 @@ class TestDatabaseAPI(unittest.TestCase):
 | 
				
			|||||||
    def setUpClass(cls):
 | 
					    def setUpClass(cls):
 | 
				
			||||||
        cls.database, cls.path = connect_database(is_test=True, module="database")
 | 
					        cls.database, cls.path = connect_database(is_test=True, module="database")
 | 
				
			||||||
        create_tables(cls.database)
 | 
					        create_tables(cls.database)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_fail_connect(cls):
 | 
					    def test_fail_connect(cls):
 | 
				
			||||||
        with cls.assertRaises(MissingModuleName):
 | 
					        with cls.assertRaises(MissingModuleName):
 | 
				
			||||||
            cls.database, cls.path = connect_database(is_test=True)
 | 
					            cls.database, cls.path = connect_database(is_test=True)
 | 
				
			||||||
@@ -35,8 +38,12 @@ class TestDatabaseAPI(unittest.TestCase):
 | 
				
			|||||||
        self.assertEqual(chat2.chat_role, 1)
 | 
					        self.assertEqual(chat2.chat_role, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_add_and_get_message(self):
 | 
					    def test_add_and_get_message(self):
 | 
				
			||||||
        add_message(message_id=1, message_text="Test Message 1", message_sender=1, answer_id=2)
 | 
					        add_message(
 | 
				
			||||||
        add_message(message_id=2, message_text="Test Message 2", message_sender=2, answer_id=1)
 | 
					            message_id=1, message_text="Test Message 1", message_sender=1, answer_id=2
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        add_message(
 | 
				
			||||||
 | 
					            message_id=2, message_text="Test Message 2", message_sender=2, answer_id=1
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        message1 = get_message(1)
 | 
					        message1 = get_message(1)
 | 
				
			||||||
        self.assertIsNotNone(message1)
 | 
					        self.assertIsNotNone(message1)
 | 
				
			||||||
@@ -49,8 +56,22 @@ class TestDatabaseAPI(unittest.TestCase):
 | 
				
			|||||||
        self.assertEqual(message2.message_text, "Test Message 2")
 | 
					        self.assertEqual(message2.message_text, "Test Message 2")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_add_and_get_user(self):
 | 
					    def test_add_and_get_user(self):
 | 
				
			||||||
        add_user(user_id=100, user_name="TestUser1", user_tag="TestTag1", user_role=0, user_stats=10, user_rep=5)
 | 
					        add_user(
 | 
				
			||||||
        add_user(user_id=101, user_name="TestUser2", user_tag="TestTag2", user_role=1, user_stats=20, user_rep=10)
 | 
					            user_id=100,
 | 
				
			||||||
 | 
					            user_name="TestUser1",
 | 
				
			||||||
 | 
					            user_tag="TestTag1",
 | 
				
			||||||
 | 
					            user_role=0,
 | 
				
			||||||
 | 
					            user_stats=10,
 | 
				
			||||||
 | 
					            user_rep=5,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        add_user(
 | 
				
			||||||
 | 
					            user_id=101,
 | 
				
			||||||
 | 
					            user_name="TestUser2",
 | 
				
			||||||
 | 
					            user_tag="TestTag2",
 | 
				
			||||||
 | 
					            user_role=1,
 | 
				
			||||||
 | 
					            user_stats=20,
 | 
				
			||||||
 | 
					            user_rep=10,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        user1 = get_user(100)
 | 
					        user1 = get_user(100)
 | 
				
			||||||
        self.assertIsNotNone(user1)
 | 
					        self.assertIsNotNone(user1)
 | 
				
			||||||
@@ -63,8 +84,22 @@ class TestDatabaseAPI(unittest.TestCase):
 | 
				
			|||||||
        self.assertEqual(user2.user_name, "TestUser2")
 | 
					        self.assertEqual(user2.user_name, "TestUser2")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_get_user_role(self):
 | 
					    def test_get_user_role(self):
 | 
				
			||||||
        add_user(user_id=102, user_name="TestUser3", user_tag="TestTag3", user_role=0, user_stats=30, user_rep=15)
 | 
					        add_user(
 | 
				
			||||||
        add_user(user_id=103, user_name="TestUser4", user_tag="TestTag4", user_role=1, user_stats=40, user_rep=20)
 | 
					            user_id=102,
 | 
				
			||||||
 | 
					            user_name="TestUser3",
 | 
				
			||||||
 | 
					            user_tag="TestTag3",
 | 
				
			||||||
 | 
					            user_role=0,
 | 
				
			||||||
 | 
					            user_stats=30,
 | 
				
			||||||
 | 
					            user_rep=15,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        add_user(
 | 
				
			||||||
 | 
					            user_id=103,
 | 
				
			||||||
 | 
					            user_name="TestUser4",
 | 
				
			||||||
 | 
					            user_tag="TestTag4",
 | 
				
			||||||
 | 
					            user_role=1,
 | 
				
			||||||
 | 
					            user_stats=40,
 | 
				
			||||||
 | 
					            user_rep=20,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        user_role1 = get_user_role(102)
 | 
					        user_role1 = get_user_role(102)
 | 
				
			||||||
        self.assertEqual(user_role1, 0)
 | 
					        self.assertEqual(user_role1, 0)
 | 
				
			||||||
@@ -73,12 +108,26 @@ class TestDatabaseAPI(unittest.TestCase):
 | 
				
			|||||||
        self.assertEqual(user_role2, 1)
 | 
					        self.assertEqual(user_role2, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_change_user_name(self):
 | 
					    def test_change_user_name(self):
 | 
				
			||||||
        add_user(user_id=104, user_name="OldName1", user_tag="TestTag5", user_role=0, user_stats=50, user_rep=25)
 | 
					        add_user(
 | 
				
			||||||
 | 
					            user_id=104,
 | 
				
			||||||
 | 
					            user_name="OldName1",
 | 
				
			||||||
 | 
					            user_tag="TestTag5",
 | 
				
			||||||
 | 
					            user_role=0,
 | 
				
			||||||
 | 
					            user_stats=50,
 | 
				
			||||||
 | 
					            user_rep=25,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        change_user_name(104, "NewName1")
 | 
					        change_user_name(104, "NewName1")
 | 
				
			||||||
        updated_user1 = get_user(104)
 | 
					        updated_user1 = get_user(104)
 | 
				
			||||||
        self.assertEqual(updated_user1.user_name, "NewName1")
 | 
					        self.assertEqual(updated_user1.user_name, "NewName1")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        add_user(user_id=105, user_name="OldName2", user_tag="TestTag6", user_role=1, user_stats=60, user_rep=30)
 | 
					        add_user(
 | 
				
			||||||
 | 
					            user_id=105,
 | 
				
			||||||
 | 
					            user_name="OldName2",
 | 
				
			||||||
 | 
					            user_tag="TestTag6",
 | 
				
			||||||
 | 
					            user_role=1,
 | 
				
			||||||
 | 
					            user_stats=60,
 | 
				
			||||||
 | 
					            user_rep=30,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        change_user_name(105, "NewName2")
 | 
					        change_user_name(105, "NewName2")
 | 
				
			||||||
        updated_user2 = get_user(105)
 | 
					        updated_user2 = get_user(105)
 | 
				
			||||||
        self.assertEqual(updated_user2.user_name, "NewName2")
 | 
					        self.assertEqual(updated_user2.user_name, "NewName2")
 | 
				
			||||||
@@ -86,8 +135,8 @@ class TestDatabaseAPI(unittest.TestCase):
 | 
				
			|||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def tearDownClass(cls):
 | 
					    def tearDownClass(cls):
 | 
				
			||||||
        cls.database.close()
 | 
					        cls.database.close()
 | 
				
			||||||
        os.system(f"rm {cls.path}")
 | 
					        os.system(f"rm {cls.path}")  # nosec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == "__main__":
 | 
				
			||||||
    unittest.main()
 | 
					    unittest.main()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,4 +10,3 @@ class NotExpectedModuleName(BaseException):
 | 
				
			|||||||
        self.message = "Не ожидалось название директории модуля"
 | 
					        self.message = "Не ожидалось название директории модуля"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        super().__init__(self.message)
 | 
					        super().__init__(self.message)
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +1,23 @@
 | 
				
			|||||||
 | 
					from aiogram import Bot
 | 
				
			||||||
from aiogram.filters import BaseFilter
 | 
					from aiogram.filters import BaseFilter
 | 
				
			||||||
from aiogram.types import Message
 | 
					from aiogram.types import Message
 | 
				
			||||||
from aiogram import Bot
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from src.modules.standard.roles.roles import Roles
 | 
					 | 
				
			||||||
from src.modules.standard.config.config import get_aproved_chat_id
 | 
					 | 
				
			||||||
from src.core.logger import log
 | 
					from src.core.logger import log
 | 
				
			||||||
 | 
					from src.modules.standard.config.config import get_aproved_chat_id
 | 
				
			||||||
 | 
					from src.modules.standard.roles.roles import Roles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ChatModerOrAdminFilter(BaseFilter):
 | 
					class ChatModerOrAdminFilter(BaseFilter):
 | 
				
			||||||
    async def __call__(self, message: Message, bot: Bot) -> bool:
 | 
					    async def __call__(self, message: Message, bot: Bot) -> bool:
 | 
				
			||||||
        user_id = message.from_user.id
 | 
					        user_id = message.from_user.id
 | 
				
			||||||
        roles = Roles()
 | 
					        roles = Roles()
 | 
				
			||||||
        admins = await bot.get_chat_administrators(message.chat.id)
 | 
					        admins = await bot.get_chat_administrators(message.chat.id)
 | 
				
			||||||
        return await roles.check_admin_permission(user_id) or \
 | 
					        return (
 | 
				
			||||||
            await roles.check_moderator_permission(user_id) or any(user_id == admin.user.id for admin in admins)
 | 
					            await roles.check_admin_permission(user_id)
 | 
				
			||||||
 | 
					            or await roles.check_moderator_permission(user_id)
 | 
				
			||||||
 | 
					            or any(user_id == admin.user.id for admin in admins)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ChatNotInApproveFilter(BaseFilter):
 | 
					class ChatNotInApproveFilter(BaseFilter):
 | 
				
			||||||
    async def __call__(self, message: Message, bot: Bot) -> bool:
 | 
					    async def __call__(self, message: Message, bot: Bot) -> bool:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,20 @@
 | 
				
			|||||||
 | 
					# flake8: noqa
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from aiogram import Bot
 | 
					from aiogram import Bot
 | 
				
			||||||
from aiogram.types import Message
 | 
					from aiogram.types import Message
 | 
				
			||||||
from src.modules.standard.config.config import get_user_role_name
 | 
					
 | 
				
			||||||
from src.modules.standard.roles.roles import Roles
 | 
					 | 
				
			||||||
from src.modules.standard.database.db_api import *
 | 
					 | 
				
			||||||
from src.core.logger import log
 | 
					from src.core.logger import log
 | 
				
			||||||
 | 
					from src.modules.standard.config.config import get_user_role_name
 | 
				
			||||||
 | 
					from src.modules.standard.database.db_api import *
 | 
				
			||||||
 | 
					from src.modules.standard.roles.roles import Roles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def get_info_answer_by_id(message: Message, bot: Bot, user_id: int):
 | 
					async def get_info_answer_by_id(message: Message, bot: Bot, user_id: int):
 | 
				
			||||||
    if get_message_ai_model(message.chat.id, message.message_id) is not None:
 | 
					    if get_message_ai_model(message.chat.id, message.message_id) is not None:
 | 
				
			||||||
        await message.reply("Это сообщение было сгенерировано ботом используя модель: " + get_message_ai_model(message.chat.id, message.message_id))
 | 
					        await message.reply(
 | 
				
			||||||
 | 
					            "Это сообщение было сгенерировано ботом используя модель: "
 | 
				
			||||||
 | 
					            + get_message_ai_model(message.chat.id, message.message_id)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
    elif user_id == bot.id:
 | 
					    elif user_id == bot.id:
 | 
				
			||||||
        await message.reply("Это сообщение было отправлено ботом")
 | 
					        await message.reply("Это сообщение было отправлено ботом")
 | 
				
			||||||
    elif get_user(user_id) is None:
 | 
					    elif get_user(user_id) is None:
 | 
				
			||||||
@@ -44,11 +51,14 @@ async def get_user_info(message: Message, bot: Bot):
 | 
				
			|||||||
        else:
 | 
					        else:
 | 
				
			||||||
            await get_info_answer_by_id(message, bot, message.from_user.id)
 | 
					            await get_info_answer_by_id(message, bot, message.from_user.id)
 | 
				
			||||||
    except Exception as e:
 | 
					    except Exception as e:
 | 
				
			||||||
        await message.reply("В вашем запросе что-то пошло не так,"
 | 
					        await message.reply(
 | 
				
			||||||
                            " попробуйте запросить информацию о пользователе по его тегу или ответив на его сообщение")
 | 
					            "В вашем запросе что-то пошло не так,"
 | 
				
			||||||
 | 
					            " попробуйте запросить информацию о пользователе по его тегу или ответив на его сообщение"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        # print(e)
 | 
					        # print(e)
 | 
				
			||||||
        await log(e)
 | 
					        await log(e)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def get_chat_info(message: Message, bot: Bot):
 | 
					async def get_chat_info(message: Message, bot: Bot):
 | 
				
			||||||
    answer = (
 | 
					    answer = (
 | 
				
			||||||
        f"*Название чата:* {message.chat.title}\n"
 | 
					        f"*Название чата:* {message.chat.title}\n"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,8 @@
 | 
				
			|||||||
from aiogram import Router, F
 | 
					# flake8: noqa
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from src.modules.standard.info.handlers import get_user_info, get_chat_info
 | 
					from aiogram import F, Router
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from src.modules.standard.info.handlers import get_chat_info, get_user_info
 | 
				
			||||||
 | 
					
 | 
				
			||||||
router = Router()
 | 
					router = Router()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,15 @@
 | 
				
			|||||||
from aiogram import Router, F, Bot, types
 | 
					# flake8: noqa
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from aiogram import Bot, F, Router, types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from src.modules.external.yandexgpt.handlers import answer_to_message
 | 
					 | 
				
			||||||
from src.modules.standard.database.db_api import *
 | 
					 | 
				
			||||||
from src.modules.standard.config.config import get_yandexgpt_start_words, get_yandexgpt_in_words, get_aproved_chat_id
 | 
					 | 
				
			||||||
from src.core.logger import log
 | 
					from src.core.logger import log
 | 
				
			||||||
 | 
					from src.modules.external.yandexgpt.handlers import answer_to_message
 | 
				
			||||||
 | 
					from src.modules.standard.config.config import (
 | 
				
			||||||
 | 
					    get_aproved_chat_id,
 | 
				
			||||||
 | 
					    get_yandexgpt_in_words,
 | 
				
			||||||
 | 
					    get_yandexgpt_start_words,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					from src.modules.standard.database.db_api import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def chat_check(message: types.Message):
 | 
					async def chat_check(message: types.Message):
 | 
				
			||||||
@@ -19,7 +25,9 @@ async def chat_check(message: types.Message):
 | 
				
			|||||||
            await log(f"Chat added: {message.chat.id} {message.chat.title}")
 | 
					            await log(f"Chat added: {message.chat.id} {message.chat.title}")
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            # print(f"Chat not in approve list: {message.chat.id} {message.chat.title}")
 | 
					            # print(f"Chat not in approve list: {message.chat.id} {message.chat.title}")
 | 
				
			||||||
            await log(f"Chat not in approve list: {message.chat.id} {message.chat.title}")
 | 
					            await log(
 | 
				
			||||||
 | 
					                f"Chat not in approve list: {message.chat.id} {message.chat.title}"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        # Проверяем обновление названия чата
 | 
					        # Проверяем обновление названия чата
 | 
				
			||||||
@@ -34,6 +42,7 @@ async def chat_check(message: types.Message):
 | 
				
			|||||||
            await log(f"Chat already exists: {message.chat.id} {message.chat.title}")
 | 
					            await log(f"Chat already exists: {message.chat.id} {message.chat.title}")
 | 
				
			||||||
            pass
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def user_check(message: types.Message):
 | 
					async def user_check(message: types.Message):
 | 
				
			||||||
    # Проверка наличия id пользователя в базе данных пользователей
 | 
					    # Проверка наличия id пользователя в базе данных пользователей
 | 
				
			||||||
    # Если пользователя нет в базе данных, то добавляем его
 | 
					    # Если пользователя нет в базе данных, то добавляем его
 | 
				
			||||||
@@ -42,17 +51,24 @@ async def user_check(message: types.Message):
 | 
				
			|||||||
    if message.from_user.last_name is None:
 | 
					    if message.from_user.last_name is None:
 | 
				
			||||||
        current_user_name = message.from_user.first_name
 | 
					        current_user_name = message.from_user.first_name
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        current_user_name = message.from_user.first_name + " " + message.from_user.last_name
 | 
					        current_user_name = (
 | 
				
			||||||
 | 
					            message.from_user.first_name + " " + message.from_user.last_name
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if get_user(message.from_user.id) is None:
 | 
					    if get_user(message.from_user.id) is None:
 | 
				
			||||||
        add_user(message.from_user.id,
 | 
					        add_user(
 | 
				
			||||||
                 message.from_user.first_name, message.from_user.last_name,
 | 
					            message.from_user.id,
 | 
				
			||||||
                 message.from_user.username)
 | 
					            message.from_user.first_name,
 | 
				
			||||||
 | 
					            message.from_user.last_name,
 | 
				
			||||||
 | 
					            message.from_user.username,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        # print(f"User added: {message.from_user.id} {message.from_user.first_name} {message.from_user.last_name}")
 | 
					        # print(f"User added: {message.from_user.id} {message.from_user.first_name} {message.from_user.last_name}")
 | 
				
			||||||
        await log(f"User added: {message.from_user.id} {current_user_name}")
 | 
					        await log(f"User added: {message.from_user.id} {current_user_name}")
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        # print(f"User already exists: {message.from_user.id} {message.from_user.first_name} {message.from_user.last_name} {message.from_user.username}")
 | 
					        # print(f"User already exists: {message.from_user.id} {message.from_user.first_name} {message.from_user.last_name} {message.from_user.username}")
 | 
				
			||||||
        await log(f"User already exists: {message.from_user.id} {current_user_name} {message.from_user.username}")
 | 
					        await log(
 | 
				
			||||||
 | 
					            f"User already exists: {message.from_user.id} {current_user_name} {message.from_user.username}"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        # Проверяем обновление имени пользователя
 | 
					        # Проверяем обновление имени пользователя
 | 
				
			||||||
        if get_user_name(message.from_user.id) != current_user_name:
 | 
					        if get_user_name(message.from_user.id) != current_user_name:
 | 
				
			||||||
            change_user_name(message.from_user.id, current_user_name)
 | 
					            change_user_name(message.from_user.id, current_user_name)
 | 
				
			||||||
@@ -62,9 +78,12 @@ async def user_check(message: types.Message):
 | 
				
			|||||||
        if get_user_tag(message.from_user.id) != message.from_user.username:
 | 
					        if get_user_tag(message.from_user.id) != message.from_user.username:
 | 
				
			||||||
            change_user_tag(message.from_user.id, message.from_user.username)
 | 
					            change_user_tag(message.from_user.id, message.from_user.username)
 | 
				
			||||||
            # print(f"User updated: {message.from_user.id} {message.from_user.username}")
 | 
					            # print(f"User updated: {message.from_user.id} {message.from_user.username}")
 | 
				
			||||||
            await log(f"User tag updated: {message.from_user.id} {message.from_user.username}")
 | 
					            await log(
 | 
				
			||||||
 | 
					                f"User tag updated: {message.from_user.id} {message.from_user.username}"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def add_stats(message: types.Message):
 | 
					async def add_stats(message: types.Message):
 | 
				
			||||||
    # Добавляем пользователю и чату статистику
 | 
					    # Добавляем пользователю и чату статистику
 | 
				
			||||||
    update_chat_all_stat(message.chat.id)
 | 
					    update_chat_all_stat(message.chat.id)
 | 
				
			||||||
@@ -79,8 +98,9 @@ async def message_processing(message: types.Message, bot: Bot):
 | 
				
			|||||||
    add_message(message)
 | 
					    add_message(message)
 | 
				
			||||||
    # Если сообщение в начале содержит слово из списка или внутри сообщения содержится слово из списка или сообщение отвечает на сообщение бота
 | 
					    # Если сообщение в начале содержит слово из списка или внутри сообщения содержится слово из списка или сообщение отвечает на сообщение бота
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((message.text.split(" ")[0] in get_yandexgpt_start_words())
 | 
					    if (message.text.split(" ")[0] in get_yandexgpt_start_words()) or (
 | 
				
			||||||
            or (any(word in message.text for word in get_yandexgpt_in_words()))):
 | 
					        any(word in message.text for word in get_yandexgpt_in_words())
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
        # print("message_processing")
 | 
					        # print("message_processing")
 | 
				
			||||||
        await log("message_processing")
 | 
					        await log("message_processing")
 | 
				
			||||||
        await answer_to_message(message, bot)
 | 
					        await answer_to_message(message, bot)
 | 
				
			||||||
@@ -92,8 +112,6 @@ async def message_processing(message: types.Message, bot: Bot):
 | 
				
			|||||||
            await answer_to_message(message, bot)
 | 
					            await answer_to_message(message, bot)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
router = Router()
 | 
					router = Router()
 | 
				
			||||||
# Если сообщение содержит текст то вызывается функция message_processing
 | 
					# Если сообщение содержит текст то вызывается функция message_processing
 | 
				
			||||||
router.message.register(message_processing, F.text)
 | 
					router.message.register(message_processing, F.text)
 | 
				
			||||||
@@ -1,12 +1,15 @@
 | 
				
			|||||||
 | 
					# flake8: noqa
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import asyncio
 | 
					import asyncio
 | 
				
			||||||
import aiohttp
 | 
					 | 
				
			||||||
import aiogram
 | 
					 | 
				
			||||||
import time
 | 
					import time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import aiogram
 | 
				
			||||||
 | 
					import aiohttp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from ...standard.config.config import *
 | 
					from ...standard.config.config import *
 | 
				
			||||||
from ...standard.roles.roles import *
 | 
					from ...standard.roles.roles import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class Moderation:
 | 
					class Moderation:
 | 
				
			||||||
    def __init__(self):
 | 
					    def __init__(self):
 | 
				
			||||||
        access_rights = get_access_rights()
 | 
					        access_rights = get_access_rights()
 | 
				
			||||||
@@ -19,24 +22,24 @@ class Moderation:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    async def time_to_seconds(time):
 | 
					    async def time_to_seconds(time):
 | 
				
			||||||
        # Конвертация текстового указания времени по типу 3h, 5m, 10s в минуты
 | 
					        # Конвертация текстового указания времени по типу 3h, 5m, 10s в минуты
 | 
				
			||||||
        if time[-1] == 'd':
 | 
					        if time[-1] == "d":
 | 
				
			||||||
            return int(time[:-1]) * 86400
 | 
					            return int(time[:-1]) * 86400
 | 
				
			||||||
        elif time[-1] == 'h':
 | 
					        elif time[-1] == "h":
 | 
				
			||||||
            return int(time[:-1]) * 3600
 | 
					            return int(time[:-1]) * 3600
 | 
				
			||||||
        elif time[-1] == 'm':
 | 
					        elif time[-1] == "m":
 | 
				
			||||||
            return int(time[:-1]) * 60
 | 
					            return int(time[:-1]) * 60
 | 
				
			||||||
        elif time[-1] == 's':
 | 
					        elif time[-1] == "s":
 | 
				
			||||||
            return int(time[:-1])
 | 
					            return int(time[:-1])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def short_time_to_time(self, time):
 | 
					    async def short_time_to_time(self, time):
 | 
				
			||||||
        # Конвертация времени в длинное название
 | 
					        # Конвертация времени в длинное название
 | 
				
			||||||
        if time[-1] == 'd':
 | 
					        if time[-1] == "d":
 | 
				
			||||||
            return str(f"{time[0:-1]} дней")
 | 
					            return str(f"{time[0:-1]} дней")
 | 
				
			||||||
        elif time[-1] == 'h':
 | 
					        elif time[-1] == "h":
 | 
				
			||||||
            return str(f"{time[0:-1]} часов")
 | 
					            return str(f"{time[0:-1]} часов")
 | 
				
			||||||
        elif time[-1] == 'm':
 | 
					        elif time[-1] == "m":
 | 
				
			||||||
            return str(f"{time[0:-1]} минут")
 | 
					            return str(f"{time[0:-1]} минут")
 | 
				
			||||||
        elif time[-1] == 's':
 | 
					        elif time[-1] == "s":
 | 
				
			||||||
            return str(f"{time[0:-1]} секунд")
 | 
					            return str(f"{time[0:-1]} секунд")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def delete_message(self, chat_id, message_id, bot: aiogram.Bot):
 | 
					    async def delete_message(self, chat_id, message_id, bot: aiogram.Bot):
 | 
				
			||||||
@@ -45,6 +48,7 @@ class Moderation:
 | 
				
			|||||||
    async def ban_user(self, chat_id, user_id, bot: aiogram.Bot):
 | 
					    async def ban_user(self, chat_id, user_id, bot: aiogram.Bot):
 | 
				
			||||||
        await bot.ban_chat_member(chat_id, user_id)
 | 
					        await bot.ban_chat_member(chat_id, user_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def mute_user(chat_id, user_id, time, bot: aiogram.Bot):
 | 
					async def mute_user(chat_id, user_id, time, bot: aiogram.Bot):
 | 
				
			||||||
    mutePermissions = {
 | 
					    mutePermissions = {
 | 
				
			||||||
        "can_send_messages": False,
 | 
					        "can_send_messages": False,
 | 
				
			||||||
@@ -60,16 +64,19 @@ async def mute_user(chat_id, user_id, time, bot: aiogram.Bot):
 | 
				
			|||||||
        "can_change_info": False,
 | 
					        "can_change_info": False,
 | 
				
			||||||
        "can_invite_users": False,
 | 
					        "can_invite_users": False,
 | 
				
			||||||
        "can_pin_messages": False,
 | 
					        "can_pin_messages": False,
 | 
				
			||||||
        "can_manage_topics": False
 | 
					        "can_manage_topics": False,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    end_time = time + int(time.time())
 | 
					    end_time = time + int(time.time())
 | 
				
			||||||
    await bot.restrict_chat_member(chat_id, user_id, until_date=end_time, **mutePermissions)
 | 
					    await bot.restrict_chat_member(
 | 
				
			||||||
 | 
					        chat_id, user_id, until_date=end_time, **mutePermissions
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def unmute_user(chat_id, user_id, bot: aiogram.Bot):
 | 
					async def unmute_user(chat_id, user_id, bot: aiogram.Bot):
 | 
				
			||||||
    await bot.restrict_chat_member(chat_id, user_id, use_independent_chat_permissions=True)
 | 
					    await bot.restrict_chat_member(
 | 
				
			||||||
 | 
					        chat_id, user_id, use_independent_chat_permissions=True
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def ban_user(chat_id, user_id, bot: aiogram.Bot):
 | 
					async def ban_user(chat_id, user_id, bot: aiogram.Bot):
 | 
				
			||||||
    await bot.ban_chat_member(chat_id, user_id)
 | 
					    await bot.ban_chat_member(chat_id, user_id)
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,9 @@
 | 
				
			|||||||
from ..database.db_api import get_user_role
 | 
					 | 
				
			||||||
from ..config.config import get_config
 | 
					from ..config.config import get_config
 | 
				
			||||||
 | 
					from ..database.db_api import get_user_role
 | 
				
			||||||
 | 
					
 | 
				
			||||||
yaml_load = get_config()
 | 
					yaml_load = get_config()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Roles:
 | 
					class Roles:
 | 
				
			||||||
    user = "USER"
 | 
					    user = "USER"
 | 
				
			||||||
    moderator = "MODERATOR"
 | 
					    moderator = "MODERATOR"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
import os
 | 
					import os
 | 
				
			||||||
import unittest
 | 
					import unittest
 | 
				
			||||||
from ...database.db_api import create_tables, connect_database, add_user
 | 
					
 | 
				
			||||||
 | 
					from ...database.db_api import add_user, connect_database, create_tables
 | 
				
			||||||
from ..roles import Roles
 | 
					from ..roles import Roles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -14,10 +15,39 @@ class TestRoles(unittest.IsolatedAsyncioTestCase):
 | 
				
			|||||||
        cls.database, cls.path = connect_database(is_test=True, module="roles")
 | 
					        cls.database, cls.path = connect_database(is_test=True, module="roles")
 | 
				
			||||||
        create_tables(cls.database)
 | 
					        create_tables(cls.database)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        add_user(user_id=1, user_name="TestUser1", user_tag="TestTag1", user_role=0, user_stats=30, user_rep=15)
 | 
					        add_user(
 | 
				
			||||||
        add_user(user_id=2, user_name="TestUser3", user_tag="TestTag3", user_role=1, user_stats=30, user_rep=15)
 | 
					            user_id=1,
 | 
				
			||||||
        add_user(user_id=3, user_name="TestUser4", user_tag="TestTag4", user_role=2, user_stats=30, user_rep=15)
 | 
					            user_name="TestUser1",
 | 
				
			||||||
        add_user(user_id=4, user_name="TestUser2", user_tag="TestTag2", user_role=3, user_stats=30, user_rep=15)
 | 
					            user_tag="TestTag1",
 | 
				
			||||||
 | 
					            user_role=0,
 | 
				
			||||||
 | 
					            user_stats=30,
 | 
				
			||||||
 | 
					            user_rep=15,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        add_user(
 | 
				
			||||||
 | 
					            user_id=2,
 | 
				
			||||||
 | 
					            user_name="TestUser3",
 | 
				
			||||||
 | 
					            user_tag="TestTag3",
 | 
				
			||||||
 | 
					            user_role=1,
 | 
				
			||||||
 | 
					            user_stats=30,
 | 
				
			||||||
 | 
					            user_rep=15,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        add_user(
 | 
				
			||||||
 | 
					            user_id=3,
 | 
				
			||||||
 | 
					            user_name="TestUser4",
 | 
				
			||||||
 | 
					            user_tag="TestTag4",
 | 
				
			||||||
 | 
					            user_role=2,
 | 
				
			||||||
 | 
					            user_stats=30,
 | 
				
			||||||
 | 
					            user_rep=15,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        add_user(
 | 
				
			||||||
 | 
					            user_id=4,
 | 
				
			||||||
 | 
					            user_name="TestUser2",
 | 
				
			||||||
 | 
					            user_tag="TestTag2",
 | 
				
			||||||
 | 
					            user_role=3,
 | 
				
			||||||
 | 
					            user_stats=30,
 | 
				
			||||||
 | 
					            user_rep=15,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def test_check_admin_permission(cls):
 | 
					    async def test_check_admin_permission(cls):
 | 
				
			||||||
        cls.assertTrue(await cls.roles.check_admin_permission(1))
 | 
					        cls.assertTrue(await cls.roles.check_admin_permission(1))
 | 
				
			||||||
        cls.assertFalse(await cls.roles.check_admin_permission(2))
 | 
					        cls.assertFalse(await cls.roles.check_admin_permission(2))
 | 
				
			||||||
@@ -32,7 +62,9 @@ class TestRoles(unittest.IsolatedAsyncioTestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    async def test_get_role_name(cls):
 | 
					    async def test_get_role_name(cls):
 | 
				
			||||||
        cls.assertEqual(await cls.roles.get_role_name(cls.roles.admin_role_id), "ADMIN")
 | 
					        cls.assertEqual(await cls.roles.get_role_name(cls.roles.admin_role_id), "ADMIN")
 | 
				
			||||||
        cls.assertEqual(await cls.roles.get_role_name(cls.roles.moderator_role_id), "MODERATOR")
 | 
					        cls.assertEqual(
 | 
				
			||||||
 | 
					            await cls.roles.get_role_name(cls.roles.moderator_role_id), "MODERATOR"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        cls.assertEqual(await cls.roles.get_role_name(cls.roles.user_role_id), "USER")
 | 
					        cls.assertEqual(await cls.roles.get_role_name(cls.roles.user_role_id), "USER")
 | 
				
			||||||
        cls.assertEqual(await cls.roles.get_role_name(cls.roles.bot_role_id), "BOT")
 | 
					        cls.assertEqual(await cls.roles.get_role_name(cls.roles.bot_role_id), "BOT")
 | 
				
			||||||
        with cls.assertRaises(ValueError):
 | 
					        with cls.assertRaises(ValueError):
 | 
				
			||||||
@@ -41,10 +73,8 @@ class TestRoles(unittest.IsolatedAsyncioTestCase):
 | 
				
			|||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def tearDownClass(cls):
 | 
					    def tearDownClass(cls):
 | 
				
			||||||
        cls.database.close()
 | 
					        cls.database.close()
 | 
				
			||||||
        os.system(f"rm {cls.path}")
 | 
					        os.system(f"rm {cls.path}")  # nosec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					 | 
				
			||||||
if __name__ == '__main__':
 | 
					 | 
				
			||||||
    unittest.main()
 | 
					    unittest.main()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,27 +1,34 @@
 | 
				
			|||||||
from aiogram import Bot
 | 
					# flake8: noqa
 | 
				
			||||||
from aiogram.types import Message
 | 
					
 | 
				
			||||||
from src.modules.standard.config.config import get_telegram_check_bot
 | 
					import asyncio
 | 
				
			||||||
from src.modules.standard.roles.roles import Roles
 | 
					import random
 | 
				
			||||||
from src.modules.standard.database.db_api import *
 | 
					 | 
				
			||||||
from src.modules.standard.moderation.moderation import mute_user, unmute_user, ban_user
 | 
					 | 
				
			||||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
 | 
					 | 
				
			||||||
from aiogram.types import inline_keyboard_button as types
 | 
					 | 
				
			||||||
import random, asyncio
 | 
					 | 
				
			||||||
from threading import Thread
 | 
					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 src.modules.standard.config.config import get_telegram_check_bot
 | 
				
			||||||
 | 
					from src.modules.standard.database.db_api import *
 | 
				
			||||||
 | 
					from src.modules.standard.moderation.moderation import ban_user, mute_user, unmute_user
 | 
				
			||||||
 | 
					from src.modules.standard.roles.roles import Roles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def create_math_task():
 | 
					async def create_math_task():
 | 
				
			||||||
    first_number = random.randint(1, 100)
 | 
					    first_number = random.randint(1, 100)  # nosec
 | 
				
			||||||
    second_number = random.randint(1, 100)
 | 
					    second_number = random.randint(1, 100)  # nosec
 | 
				
			||||||
    answer = first_number + second_number
 | 
					    answer = first_number + second_number
 | 
				
			||||||
    fake_answers = []
 | 
					    fake_answers = []
 | 
				
			||||||
    for i in range(3):
 | 
					    for i in range(3):
 | 
				
			||||||
        diff = random.randint(1, 10)
 | 
					        diff = random.randint(1, 10)  # nosec
 | 
				
			||||||
        diff_sign = random.choice(["+", "-"])
 | 
					        diff_sign = random.choice(["+", "-"])  # nosec
 | 
				
			||||||
        fake_answers.append(answer + diff if diff_sign == "+" else answer - diff)
 | 
					        fake_answers.append(answer + diff if diff_sign == "+" else answer - diff)
 | 
				
			||||||
    fake_answers.append(answer)
 | 
					    fake_answers.append(answer)
 | 
				
			||||||
    random.shuffle(fake_answers)
 | 
					    random.shuffle(fake_answers)
 | 
				
			||||||
    return [answer, first_number, second_number, fake_answers]
 | 
					    return [answer, first_number, second_number, fake_answers]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def ban_user_timer(chat_id: int, user_id: int, time: int, bot: Bot):
 | 
					async def ban_user_timer(chat_id: int, user_id: int, time: int, bot: Bot):
 | 
				
			||||||
    await asyncio.sleep(time)
 | 
					    await asyncio.sleep(time)
 | 
				
			||||||
    if get_user(user_id) is not None:
 | 
					    if get_user(user_id) is not None:
 | 
				
			||||||
@@ -30,8 +37,6 @@ async def ban_user_timer(chat_id: int, user_id: int, time: int, bot: Bot):
 | 
				
			|||||||
        await ban_user()
 | 
					        await ban_user()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async def check_new_user(message: Message, bot: Bot):
 | 
					async def check_new_user(message: Message, bot: Bot):
 | 
				
			||||||
    print("check_new_user")
 | 
					    print("check_new_user")
 | 
				
			||||||
    if get_telegram_check_bot():
 | 
					    if get_telegram_check_bot():
 | 
				
			||||||
@@ -39,7 +44,10 @@ async def check_new_user(message: Message, bot: Bot):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if get_user(message.from_user.id) is None:
 | 
					        if get_user(message.from_user.id) is None:
 | 
				
			||||||
            # Выдаём пользователю ограничение на отправку сообщений на 3 минуты
 | 
					            # Выдаём пользователю ограничение на отправку сообщений на 3 минуты
 | 
				
			||||||
            ban_task = Thread(target=ban_user_timer, args=(message.chat.id, message.from_user.id, 180, bot))
 | 
					            ban_task = Thread(
 | 
				
			||||||
 | 
					                target=ban_user_timer,
 | 
				
			||||||
 | 
					                args=(message.chat.id, message.from_user.id, 180, bot),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
            ban_task.start()
 | 
					            ban_task.start()
 | 
				
			||||||
            # Создаём задачу с отложенным выполнением на 3 минуты
 | 
					            # Создаём задачу с отложенным выполнением на 3 минуты
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -48,27 +56,31 @@ async def check_new_user(message: Message, bot: Bot):
 | 
				
			|||||||
            builder = InlineKeyboardBuilder()
 | 
					            builder = InlineKeyboardBuilder()
 | 
				
			||||||
            for answer in math_task[3]:
 | 
					            for answer in math_task[3]:
 | 
				
			||||||
                if answer == math_task[0]:
 | 
					                if answer == math_task[0]:
 | 
				
			||||||
                    builder.add(types.InlineKeyboardButton(
 | 
					                    builder.add(
 | 
				
			||||||
                        text=answer,
 | 
					                        types.InlineKeyboardButton(
 | 
				
			||||||
                        callback_data=f"check_math_task_true")
 | 
					                            text=answer, callback_data=f"check_math_task_true"
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    builder.add(types.InlineKeyboardButton(
 | 
					                    builder.add(
 | 
				
			||||||
                        text=answer,
 | 
					                        types.InlineKeyboardButton(
 | 
				
			||||||
                        callback_data=f"check_math_task_false")
 | 
					                            text=answer, callback_data=f"check_math_task_false"
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
            await message.reply(
 | 
					            await message.reply(
 | 
				
			||||||
                f"Приветствую, {message.from_user.first_name}!\n"
 | 
					                f"Приветствую, {message.from_user.first_name}!\n"
 | 
				
			||||||
                f"Для продолжения работы с ботом, пожалуйста, решите математический пример в течении 3х минут:\n"
 | 
					                f"Для продолжения работы с ботом, пожалуйста, решите математический пример в течении 3х минут:\n"
 | 
				
			||||||
                f"*{text}*",
 | 
					                f"*{text}*",
 | 
				
			||||||
                reply_markup=builder.as_markup()
 | 
					                reply_markup=builder.as_markup(),
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def math_task_true(message: Message, bot: Bot):
 | 
					async def math_task_true(message: Message, bot: Bot):
 | 
				
			||||||
    await message.reply(f"Верно! Добро пожаловать в чат {message.from_user.first_name}")
 | 
					    await message.reply(f"Верно! Добро пожаловать в чат {message.from_user.first_name}")
 | 
				
			||||||
    await unmute_user(message.chat.id, message.from_user.id, bot)
 | 
					    await unmute_user(message.chat.id, message.from_user.id, bot)
 | 
				
			||||||
    add_user(message.from_user.id,
 | 
					    add_user(
 | 
				
			||||||
             message.from_user.first_name + ' ' + message.from_user.last_name,
 | 
					        message.from_user.id,
 | 
				
			||||||
             message.from_user.username)
 | 
					        message.from_user.first_name + " " + message.from_user.last_name,
 | 
				
			||||||
 | 
					        message.from_user.username,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    pass
 | 
					    pass
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
from aiogram import Router, F
 | 
					from aiogram import F, Router
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from src.modules.standard.welcome.handlers import check_new_user
 | 
					from src.modules.standard.welcome.handlers import check_new_user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -7,4 +7,6 @@ router = Router()
 | 
				
			|||||||
# Если в чат пришел новый пользователь
 | 
					# Если в чат пришел новый пользователь
 | 
				
			||||||
router.message.register(check_new_user, F.new_chat_members.exists())
 | 
					router.message.register(check_new_user, F.new_chat_members.exists())
 | 
				
			||||||
# Ловин колбеки от кнопок с callback_data=f"check_math_task_true"
 | 
					# Ловин колбеки от кнопок с callback_data=f"check_math_task_true"
 | 
				
			||||||
router.callback_query.register(check_new_user, F.callback_data == "check_math_task_true")
 | 
					router.callback_query.register(
 | 
				
			||||||
 | 
					    check_new_user, F.callback_data == "check_math_task_true"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,13 +9,14 @@ class Path:
 | 
				
			|||||||
    modules_standard: str
 | 
					    modules_standard: str
 | 
				
			||||||
    modules_custom: str
 | 
					    modules_custom: str
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _get_paths(path_to_json: str):
 | 
					def _get_paths(path_to_json: str):
 | 
				
			||||||
    with open(path_to_json, encoding="utf8") as f:
 | 
					    with open(path_to_json, encoding="utf8") as f:
 | 
				
			||||||
        paths = loads(f.read())
 | 
					        paths = loads(f.read())
 | 
				
			||||||
    return Path(
 | 
					    return Path(
 | 
				
			||||||
        core=paths["core"],
 | 
					        core=paths["core"],
 | 
				
			||||||
        modules_standard=paths["modules standard"],
 | 
					        modules_standard=paths["modules standard"],
 | 
				
			||||||
        modules_custom=paths["modules custom"]
 | 
					        modules_custom=paths["modules custom"],
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user