xync-bot 0.3.5__py3-none-any.whl → 0.3.7.dev1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of xync-bot might be problematic. Click here for more details.

xync_bot/__init__.py CHANGED
@@ -0,0 +1,20 @@
1
+ import logging
2
+ from asyncio import run
3
+
4
+ from PGram import Bot
5
+ from aiogram.client.default import DefaultBotProperties
6
+ from x_model import init_db
7
+
8
+ from xync_bot.routers.cond import r
9
+
10
+ if __name__ == "__main__":
11
+ from xync_bot.loader import TOKEN, TORM
12
+
13
+ logging.basicConfig(level=logging.INFO)
14
+
15
+ async def main() -> None:
16
+ cn = await init_db(TORM)
17
+ bot = Bot(TOKEN, [r], cn, default=DefaultBotProperties(parse_mode="HTML"))
18
+ await bot.start()
19
+
20
+ run(main())
xync_bot/loader.py ADDED
@@ -0,0 +1,21 @@
1
+ from dotenv import load_dotenv
2
+ from os import getenv as env
3
+
4
+ from xync_schema import models
5
+
6
+ load_dotenv()
7
+
8
+ PG_DSN = (
9
+ f"postgres://{env('POSTGRES_USER')}:{env('POSTGRES_PASSWORD')}@{env('POSTGRES_HOST', 'dbs')}"
10
+ f":{env('POSTGRES_PORT', 5432)}/{env('POSTGRES_DB', env('POSTGRES_USER'))}"
11
+ )
12
+ TOKEN = env("TOKEN")
13
+ # API_URL = "https://" + env("API_DOMAIN")
14
+ # WH_URL = API_URL + "/wh/" + TOKEN
15
+
16
+ TORM = {
17
+ "connections": {"default": PG_DSN},
18
+ "apps": {"models": {"models": [models, "aerich.models"]}},
19
+ "use_tz": False,
20
+ "timezone": "UTC",
21
+ }
@@ -0,0 +1,179 @@
1
+ import re
2
+ from enum import IntEnum
3
+ from inspect import isclass
4
+ from typing import Coroutine
5
+
6
+ from aiogram import Router, F
7
+ from aiogram.filters import CommandStart
8
+ from aiogram.fsm.context import FSMContext
9
+ from aiogram.types import (
10
+ Message,
11
+ ReplyKeyboardMarkup,
12
+ KeyboardButton,
13
+ InlineKeyboardMarkup,
14
+ InlineKeyboardButton,
15
+ CallbackQuery,
16
+ # ReplyKeyboardRemove,
17
+ )
18
+ from cyrtranslit import to_latin
19
+ from xync_schema import models
20
+ from xync_schema.enums import SynonymType, Party, Slip, AbuserType, NameType, Boundary
21
+
22
+ r = Router()
23
+
24
+
25
+ async def wrap_cond(txt: str):
26
+ bnks = await models.Synonym.filter(typ=SynonymType.bank)
27
+ bnks = "|".join("\\b" + b.txt + ("\\b" if b.boundary & Boundary.right else "") for b in bnks)
28
+ for syn in await models.Synonym.all():
29
+ lb, rb = "\\b" if syn.boundary & Boundary.left else "", "\\b" if syn.boundary & Boundary.right else ""
30
+ if syn.typ == SynonymType.bank_side:
31
+ syn.txt.replace("#banks#", f"({bnks})")
32
+ if syn.is_re or syn.txt in txt:
33
+ pattern = re.compile(lb + syn.txt + rb)
34
+ if match := re.search(pattern, txt):
35
+ g = match.group()
36
+ val, hval = await get_val(syn.typ, syn.val)
37
+ val = syn.typ.name + (f'="{hval}"' if hval else "")
38
+ txt = re.sub(pattern, f"<code>{g}</code><tg-spoiler>[{val}]</tg-spoiler>", txt)
39
+ return txt
40
+
41
+
42
+ async def cbanks(bnid: str) -> list[tuple[int, str]]:
43
+ beginning = to_latin(bnid[:2], lang_code="ru")
44
+ return await models.Pm.filter(norm__startswith=beginning, bank=True).values_list("id", "norm")
45
+
46
+
47
+ async def cppo(txt: str) -> list[tuple[int, str]]:
48
+ opts = re.findall(r"\d+", txt) or [1, 2, 3, 5, 10]
49
+ return [(o, str(o)) for o in opts]
50
+
51
+
52
+ synopts: dict[SynonymType, list[str] | type(IntEnum) | None | Coroutine] = {
53
+ SynonymType.name: ["not_slavic", "slavic"],
54
+ SynonymType.ppo: cppo,
55
+ SynonymType.from_party: Party,
56
+ SynonymType.to_party: Party,
57
+ SynonymType.slip_req: Slip,
58
+ SynonymType.slip_send: Slip,
59
+ SynonymType.abuser: AbuserType,
60
+ SynonymType.scale: ["1", "10", "100", "1000"],
61
+ SynonymType.slavic: NameType,
62
+ SynonymType.mtl_like: None,
63
+ SynonymType.bank: cbanks,
64
+ SynonymType.bank_side: ["except", "only"],
65
+ }
66
+ rkm = ReplyKeyboardMarkup(
67
+ keyboard=[
68
+ [KeyboardButton(text="ppo"), KeyboardButton(text="abuser")],
69
+ [KeyboardButton(text="from_party"), KeyboardButton(text="to_party")],
70
+ [KeyboardButton(text="slip_send"), KeyboardButton(text="slip_req")],
71
+ [KeyboardButton(text="name"), KeyboardButton(text="slavic")],
72
+ [KeyboardButton(text="scale"), KeyboardButton(text="mtl_like")],
73
+ [KeyboardButton(text="bank"), KeyboardButton(text="bank_side")],
74
+ ],
75
+ one_time_keyboard=True,
76
+ )
77
+
78
+
79
+ async def get_val(typ: SynonymType.__class__, val: str) -> tuple[SynonymType | int | bool, str]:
80
+ if isinstance(val, str) and val.isnumeric():
81
+ val = int(val)
82
+ if isclass(lst := synopts[typ]) and issubclass(lst, IntEnum):
83
+ return (v := lst(val)), v.name
84
+ elif isinstance(lst, list):
85
+ return val, lst[val]
86
+ elif typ == SynonymType.bank:
87
+ return val, (await models.Pm[val]).norm
88
+ return val, val
89
+
90
+
91
+ async def btns(typ: SynonymType.__class__, txt: str = None) -> InlineKeyboardMarkup | None:
92
+ if lst := synopts[typ]:
93
+ if isinstance(lst, list):
94
+ kb = [[InlineKeyboardButton(text=n, callback_data=f"st:{typ.name}:{i}")] for i, n in enumerate(lst)]
95
+ elif isclass(lst) and issubclass(lst, IntEnum):
96
+ kb = [[InlineKeyboardButton(text=i.name, callback_data=f"st:{typ.name}:{i.value}")] for i in lst]
97
+ else:
98
+ kb = [[InlineKeyboardButton(text=n, callback_data=f"st:{typ.name}:{i}")] for i, n in await lst(txt)]
99
+ return InlineKeyboardMarkup(inline_keyboard=kb)
100
+ else:
101
+ return lst
102
+
103
+
104
+ @r.message(CommandStart())
105
+ async def start(msg: Message, state: FSMContext):
106
+ cond = await models.Cond.filter(parsed__isnull=True).order_by("-created_at").first().prefetch_related("parsed")
107
+ await state.set_data({"cid": cond.id, "cond_txt": cond.raw_txt})
108
+ await msg.reply(await wrap_cond(cond.raw_txt), reply_markup=rkm)
109
+
110
+
111
+ @r.message(F.quote)
112
+ async def got_synonym(msg: Message, state: FSMContext):
113
+ if not (msg.text in {st.name for st in SynonymType} and SynonymType[msg.text]):
114
+ return await msg.reply_text(
115
+ f'Нет раздела "{msg.text}", не пиши текст сам, выдели кусок из моего сообщения,'
116
+ f"ответь на него, выбери кнопку раздела"
117
+ )
118
+ if not msg.quote:
119
+ return await msg.reply_text(f"Вы забыли выделить кусок текста для {msg.text}")
120
+ if typ := SynonymType[msg.text]:
121
+ await state.update_data({"syntext": msg.quote.text, "cmsg": msg.reply_to_message})
122
+ await models.Synonym.update_or_create({"typ": typ}, txt=msg.quote.text)
123
+ if rm := await btns(typ, msg.quote.text):
124
+ return await msg.answer("Уточните", reply_markup=rm, reply_to_message_id=msg.message_id)
125
+ await syn_result(msg, f"st:{typ.name}:1", state)
126
+ return None
127
+
128
+
129
+ @r.callback_query()
130
+ async def got_synonym_val(cbq: CallbackQuery, state: FSMContext):
131
+ await syn_result(cbq.message, cbq.data, state)
132
+
133
+
134
+ async def syn_result(msg: Message, data: str, state: FSMContext):
135
+ t, st, sv = data.split(":")
136
+ if t == "st":
137
+ typ = SynonymType[st]
138
+ val, hval = await get_val(typ, sv)
139
+ syntext = await state.get_value("syntext")
140
+ cid = await state.get_value("cid")
141
+ syn, _ = await models.Synonym.update_or_create({"val": val}, typ=typ, txt=syntext)
142
+ await models.CondParsed.update_or_create({typ.name: val}, cond_id=cid)
143
+ await msg.reply(
144
+ f'Текст "{syntext}" определен как синоним для `{typ.name}` со значением {hval}',
145
+ reply_markup=InlineKeyboardMarkup(
146
+ inline_keyboard=[
147
+ [
148
+ InlineKeyboardButton(text="Готово! Давай новый", callback_data=f"cond:complete:{cid}"),
149
+ InlineKeyboardButton(text="Продолжить с этим текстом", callback_data=f"cond:process:{cid}"),
150
+ ]
151
+ ]
152
+ ),
153
+ )
154
+ # await msg.reply_to_message.delete()
155
+ # await msg.delete()
156
+ # await cmsg.edit_text(wrapped_txt)
157
+
158
+ elif t == "cond":
159
+ if st == "complete":
160
+ await models.CondParsed.update_or_create({"parsed": True}, cond_id=int(sv))
161
+ await start(msg, state)
162
+ else:
163
+ wrapped_txt = await wrap_cond(await state.get_value("cond_txt"))
164
+ # cmsg: Message = await state.get_value('cmsg')
165
+ await msg.reply(wrapped_txt, reply_markup=rkm)
166
+ else:
167
+ await msg.reply("Где я?")
168
+
169
+
170
+ @r.message(F.reply_to_message)
171
+ async def clear(msg: Message):
172
+ await msg.reply_to_message.delete_reply_markup()
173
+ await msg.delete()
174
+
175
+
176
+ @r.message()
177
+ async def unknown(msg: Message):
178
+ # user = await User.get(username_id=msg.from_user.id)
179
+ await msg.delete()
@@ -15,9 +15,9 @@ from aiogram.types import (
15
15
  WebAppInfo,
16
16
  )
17
17
  from aiogram.utils.deep_linking import create_start_link
18
- from xync_bot.handlers import user_upsert
19
18
  from xync_schema.models import User, Order, Msg, Forum
20
19
 
20
+ from xync_bot.routers import user_upsert
21
21
  from xync_bot.shared import NavCallbackData
22
22
 
23
23
  main = Router()
xync_bot/typs.py ADDED
File without changes
@@ -1,17 +1,19 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xync-bot
3
- Version: 0.3.5
3
+ Version: 0.3.7.dev1
4
4
  Summary: Telegram bot with web app for xync net
5
5
  Author-email: Artemiev <mixartemev@gmail.com>
6
- License: EULA
6
+ License-Expression: GPL-3.0-or-later
7
7
  Project-URL: Homepage, https://gitlab.com/xync/back/tg-bot
8
8
  Project-URL: Repository, https://gitlab.com/xync/back/tg-bot
9
- Keywords: aiogram,xync-net
9
+ Keywords: aiogram,cyrtranslit,xync-net
10
10
  Requires-Python: >=3.12
11
- Description-Content-Type: text/markdown
12
11
  Requires-Dist: xync-schema
13
12
  Provides-Extra: dev
13
+ Requires-Dist: PGram; extra == "dev"
14
+ Requires-Dist: pre-commit; extra == "dev"
14
15
  Requires-Dist: pytest; extra == "dev"
15
16
  Requires-Dist: python-dotenv; extra == "dev"
17
+ Requires-Dist: setuptools-scm; extra == "dev"
16
18
  Requires-Dist: build; extra == "dev"
17
19
  Requires-Dist: twine; extra == "dev"
@@ -0,0 +1,16 @@
1
+ xync_bot/__init__.py,sha256=DxSf_OvNstlmK9_-z7Q-3ld1SC6Hd6gWxBlFffd7Cjo,490
2
+ xync_bot/loader.py,sha256=wnhRRMJ6KSFAFZnDBGg9mbbktq34VHtcNSt89WuPn04,558
3
+ xync_bot/shared.py,sha256=MlKkTrsT29l7fF6-qAN9FO14cSuXuOuYxbNY5F4S2w4,137
4
+ xync_bot/typs.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ xync_bot/routers/__init__.py,sha256=0CwHTSgAWzKRZ7PtsaLGA8PtjWQtZqsEXKyncNbCKLA,374
6
+ xync_bot/routers/main.py,sha256=ZfgEX17_QaZ8CVEQqNZnNFt8RLfr6xfZ_A2ZGJoe-Oo,9520
7
+ xync_bot/routers/order.py,sha256=ZKWDLyiWrXzcR-aHKLBTBCACwp-P0Vvnr22T-EuLHaM,274
8
+ xync_bot/routers/photo.py,sha256=aq6ImIOoZQYTW-lEy26qjgj5TYAuk4bQjgiCv64mPJs,1203
9
+ xync_bot/routers/vpn.py,sha256=qKK55UrjEZeDvu7ljWXNUFBFgXTPTIEaCT2OAmKWky4,2219
10
+ xync_bot/routers/xicon.png,sha256=O57_kvzhVcCXSoGYZ61m0dW9pizY6gxR8Yj5aeCP0RQ,429283
11
+ xync_bot/routers/cond/__init__.py,sha256=n9MLqu0tENaA3n2-WSh7XAelXxyFJtCQGdd6lqP7GmI,7248
12
+ xync_bot/routers/cond/cond.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ xync_bot-0.3.7.dev1.dist-info/METADATA,sha256=g2DghtBKWq9Igmbx6p_sKymDH473mWvq-fdogyuu980,700
14
+ xync_bot-0.3.7.dev1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
+ xync_bot-0.3.7.dev1.dist-info/top_level.txt,sha256=O2IjMc1ryAf0rwIXWohSNT5Kzcs9johgKRDz8lCC0rs,9
16
+ xync_bot-0.3.7.dev1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,13 +0,0 @@
1
- xync_bot/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- xync_bot/shared.py,sha256=MlKkTrsT29l7fF6-qAN9FO14cSuXuOuYxbNY5F4S2w4,137
3
- xync_bot/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- xync_bot/handlers/__init__.py,sha256=0CwHTSgAWzKRZ7PtsaLGA8PtjWQtZqsEXKyncNbCKLA,374
5
- xync_bot/handlers/main.py,sha256=eIgorrJXzRJfsO7fx1XxVHFJDfMiJyWt7myS4qSqS8U,9521
6
- xync_bot/handlers/order.py,sha256=ZKWDLyiWrXzcR-aHKLBTBCACwp-P0Vvnr22T-EuLHaM,274
7
- xync_bot/handlers/photo.py,sha256=aq6ImIOoZQYTW-lEy26qjgj5TYAuk4bQjgiCv64mPJs,1203
8
- xync_bot/handlers/vpn.py,sha256=qKK55UrjEZeDvu7ljWXNUFBFgXTPTIEaCT2OAmKWky4,2219
9
- xync_bot/handlers/xicon.png,sha256=O57_kvzhVcCXSoGYZ61m0dW9pizY6gxR8Yj5aeCP0RQ,429283
10
- xync_bot-0.3.5.dist-info/METADATA,sha256=Ixje9jeQi2Xf6sJXWbag5W2Tbz3TrsfLv5-2QIpaaEk,575
11
- xync_bot-0.3.5.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
12
- xync_bot-0.3.5.dist-info/top_level.txt,sha256=O2IjMc1ryAf0rwIXWohSNT5Kzcs9johgKRDz8lCC0rs,9
13
- xync_bot-0.3.5.dist-info/RECORD,,
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes