xync-bot 0.3.7.dev1__py3-none-any.whl → 0.3.7.dev4__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
@@ -5,7 +5,10 @@ from PGram import Bot
5
5
  from aiogram.client.default import DefaultBotProperties
6
6
  from x_model import init_db
7
7
 
8
- from xync_bot.routers.cond import r
8
+ from xync_bot.routers.cond import cr
9
+
10
+ # from xync_bot.routers.main import mr
11
+ from xync_bot.routers.pay.main import pay as pay
9
12
 
10
13
  if __name__ == "__main__":
11
14
  from xync_bot.loader import TOKEN, TORM
@@ -14,7 +17,7 @@ if __name__ == "__main__":
14
17
 
15
18
  async def main() -> None:
16
19
  cn = await init_db(TORM)
17
- bot = Bot(TOKEN, [r], cn, default=DefaultBotProperties(parse_mode="HTML"))
20
+ bot = Bot(TOKEN, [cr, pay], cn, default=DefaultBotProperties(parse_mode="HTML"))
18
21
  await bot.start()
19
22
 
20
23
  run(main())
@@ -1,8 +0,0 @@
1
- from aiogram.types import User
2
- from aiogram.utils.web_app import WebAppUser
3
- from xync_schema import models
4
-
5
-
6
- async def user_upsert(u: User | WebAppUser, blocked: bool = None) -> tuple[User, bool]:
7
- user_in: models.User.Upd = await models.User.tg2in(u, blocked)
8
- return await models.User.update_or_create(user_in.model_dump(exclude_none=True, exclude={"id"}), id=u.id)
@@ -1,114 +1,33 @@
1
- import re
2
- from enum import IntEnum
3
- from inspect import isclass
4
- from typing import Coroutine
5
-
6
1
  from aiogram import Router, F
7
- from aiogram.filters import CommandStart
2
+ from aiogram.exceptions import TelegramBadRequest
3
+ from aiogram.filters import Command
8
4
  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
5
+ from aiogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery
19
6
  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())
7
+ from xync_schema.enums import SynonymType
8
+
9
+ from xync_bot.routers.cond.func import wrap_cond, get_val, btns, rkm, ikm, SynTypeCd, CondCd
10
+
11
+ cr = Router()
12
+
13
+
14
+ @cr.message(Command("cond"))
105
15
  async def start(msg: Message, state: FSMContext):
16
+ await msg.reply('Заполняем синонимы признаков условий объявлений: "ссылка на инструкцию"', reply_markup=rkm)
17
+ await show_new_cond(msg, state)
18
+
19
+
20
+ async def show_new_cond(msg: Message, state: FSMContext):
106
21
  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)
22
+ await state.set_data({"cond": cond})
23
+ await show_cond(msg, cond)
109
24
 
110
25
 
111
- @r.message(F.quote)
26
+ async def show_cond(msg: Message, cond: models.Cond):
27
+ await msg.answer(await wrap_cond(cond), reply_markup=ikm)
28
+
29
+
30
+ @cr.message(F.quote)
112
31
  async def got_synonym(msg: Message, state: FSMContext):
113
32
  if not (msg.text in {st.name for st in SynonymType} and SynonymType[msg.text]):
114
33
  return await msg.reply_text(
@@ -122,58 +41,57 @@ async def got_synonym(msg: Message, state: FSMContext):
122
41
  await models.Synonym.update_or_create({"typ": typ}, txt=msg.quote.text)
123
42
  if rm := await btns(typ, msg.quote.text):
124
43
  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)
44
+ await syn_result(msg, SynTypeCd(typ=typ.name, val=1), state)
126
45
  return None
127
46
 
128
47
 
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
- ]
48
+ @cr.callback_query(SynTypeCd.filter())
49
+ async def got_synonym_val(cbq: CallbackQuery, callback_data: SynTypeCd, state: FSMContext):
50
+ await syn_result(cbq.message, callback_data, state)
51
+
52
+
53
+ async def syn_result(msg: Message, cbd: SynTypeCd, state: FSMContext):
54
+ cond: models.Cond = await state.get_value("cond")
55
+ typ = SynonymType[cbd.typ]
56
+ val, hval = await get_val(typ, cbd.val)
57
+ syntext = await state.get_value("syntext")
58
+ syn, _ = await models.Synonym.update_or_create({"val": val}, typ=typ, txt=syntext)
59
+ await models.CondParsed.update_or_create({typ.name: val}, cond_id=cond.id)
60
+ await msg.answer(
61
+ f'Текст "{syntext}" определен как синоним для `{typ.name}` со значением {hval}',
62
+ reply_markup=InlineKeyboardMarkup(
63
+ inline_keyboard=[
64
+ [
65
+ InlineKeyboardButton(text="Готово! Давай новый", callback_data="cond:complete"),
66
+ InlineKeyboardButton(text="Продолжить с этим текстом", callback_data="cond:continue"),
151
67
  ]
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()
68
+ ]
69
+ ),
70
+ )
71
+
72
+
73
+ @cr.callback_query(CondCd.filter())
74
+ async def got_action(cbq: CallbackQuery, callback_data: CondCd, state: FSMContext):
75
+ cond: models.Cond = await state.get_value("cond")
76
+ if callback_data.act == "complete":
77
+ await models.CondParsed.update_or_create({"parsed": True}, cond=cond)
78
+ await show_new_cond(cbq.message, state)
79
+ elif callback_data.act == "pass":
80
+ await show_new_cond(cbq.message, state)
81
+ elif callback_data.act == "refresh":
82
+ try:
83
+ await cbq.message.edit_text(await wrap_cond(cond), reply_markup=ikm)
84
+ except TelegramBadRequest as e:
85
+ if "message is not modified:" in e.message:
86
+ return await cbq.answer("Текст не изменился")
87
+ raise e
88
+ elif callback_data.act == "continue":
89
+ await (await state.get_value("cmsg")).delete()
90
+ await show_cond(cbq.message, cond)
91
+ return await cbq.answer(callback_data.act)
92
+
93
+
94
+ @cr.message()
177
95
  async def unknown(msg: Message):
178
96
  # user = await User.get(username_id=msg.from_user.id)
179
97
  await msg.delete()
@@ -0,0 +1,118 @@
1
+ import re
2
+ from enum import IntEnum
3
+ from inspect import isclass
4
+ from typing import Coroutine
5
+
6
+ from aiogram.filters.callback_data import CallbackData
7
+ from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ReplyKeyboardMarkup, KeyboardButton
8
+ from cyrtranslit import to_latin
9
+ from xync_schema import models
10
+ from xync_schema.enums import SynonymType, Boundary, Party, Slip, AbuserType, NameType
11
+
12
+
13
+ class SynTypeCd(CallbackData, prefix="st"):
14
+ typ: str
15
+ val: int
16
+
17
+
18
+ class CondCd(CallbackData, prefix="cond"):
19
+ act: str
20
+
21
+
22
+ async def wrap_cond(cond: models.Cond):
23
+ bnks = await models.Synonym.filter(typ=SynonymType.bank)
24
+ bnks = "|".join("\\b" + b.txt + ("\\b" if b.boundary & Boundary.right else "") for b in bnks)
25
+ ad = await models.Ad.filter(cond=cond).order_by("-updated_at").prefetch_related("ex", "pair_side").first()
26
+ hdr = ("SELL" if ad.pair_side.is_sell else "BUY") + f":{ad.price} [{ad.min_fiat}]"
27
+ if (mx := (ad.max_fiat or ad.amount)) > ad.min_fiat:
28
+ hdr += f"->[{mx}]"
29
+ txt = cond.raw_txt
30
+ for syn in await models.Synonym.all():
31
+ lb, rb = "\\b" if syn.boundary & Boundary.left else "", "\\b" if syn.boundary & Boundary.right else ""
32
+ if syn.typ == SynonymType.bank_side:
33
+ syn.txt.replace("#banks#", f"({bnks})")
34
+ if syn.is_re or syn.txt in txt:
35
+ pattern = re.compile(lb + syn.txt + rb)
36
+ if match := re.search(pattern, txt):
37
+ g = match.group()
38
+ val, hval = await get_val(syn.typ, syn.val)
39
+ val = syn.typ.name + (f'="{hval}"' if hval else "")
40
+ txt = re.sub(pattern, f"<code>{g}</code><tg-spoiler>[{val}]</tg-spoiler>", txt)
41
+ return f"<blockquote>{hdr} {ad.ex.name}</blockquote>{txt}"
42
+
43
+
44
+ async def cbanks(bnid: str) -> list[tuple[int, str]]:
45
+ beginning = to_latin(bnid[:2], lang_code="ru")
46
+ return await models.Pm.filter(norm__startswith=beginning, bank=True).values_list("id", "norm")
47
+
48
+
49
+ async def cppo(txt: str) -> list[tuple[int, str]]:
50
+ opts = re.findall(r"\d+", txt) or [1, 1000, 5000]
51
+ return [(o, str(o)) for o in opts]
52
+
53
+
54
+ async def contact(txt: str) -> list[tuple[int, str]]: ...
55
+
56
+
57
+ synopts: dict[SynonymType, list[str] | type(IntEnum) | None | Coroutine] = {
58
+ SynonymType.name: ["not_slavic", "slavic"],
59
+ SynonymType.ppo: cppo,
60
+ SynonymType.from_party: Party,
61
+ SynonymType.to_party: Party,
62
+ SynonymType.slip_req: Slip,
63
+ SynonymType.slip_send: Slip,
64
+ SynonymType.abuser: AbuserType,
65
+ SynonymType.scale: ["1", "100", "1000", "5000"],
66
+ SynonymType.slavic: NameType,
67
+ SynonymType.mtl_like: None,
68
+ SynonymType.bank: cbanks,
69
+ SynonymType.bank_side: ["except", "only"],
70
+ SynonymType.sbp_strict: ["no", "sbp", "card"],
71
+ SynonymType.contact: contact,
72
+ }
73
+
74
+ rkm = ReplyKeyboardMarkup(
75
+ keyboard=[
76
+ [KeyboardButton(text="ppo"), KeyboardButton(text="abuser")],
77
+ [KeyboardButton(text="from_party"), KeyboardButton(text="to_party")],
78
+ [KeyboardButton(text="slip_send"), KeyboardButton(text="slip_req")],
79
+ [KeyboardButton(text="name"), KeyboardButton(text="slavic")],
80
+ [KeyboardButton(text="scale"), KeyboardButton(text="mtl_like")],
81
+ [KeyboardButton(text="bank"), KeyboardButton(text="bank_side")],
82
+ [KeyboardButton(text="sbp_strict"), KeyboardButton(text="contact")],
83
+ ],
84
+ # one_time_keyboard=True,
85
+ )
86
+ ikm = InlineKeyboardMarkup(
87
+ inline_keyboard=[
88
+ [
89
+ InlineKeyboardButton(text="Обновить", callback_data="cond:refresh"),
90
+ InlineKeyboardButton(text="Пропустить", callback_data="cond:pass"),
91
+ ]
92
+ ]
93
+ )
94
+
95
+
96
+ async def get_val(typ: SynonymType.__class__, val: str | int) -> tuple[SynonymType | int | bool, str]:
97
+ if isinstance(val, str) and val.isnumeric():
98
+ val = int(val)
99
+ if isclass(lst := synopts[typ]) and issubclass(lst, IntEnum):
100
+ return (v := lst(val)), v.name
101
+ elif isinstance(lst, list):
102
+ return val, lst[val]
103
+ elif typ == SynonymType.bank:
104
+ return val, (await models.Pm[val]).norm
105
+ return val, val
106
+
107
+
108
+ async def btns(typ: SynonymType.__class__, txt: str = None) -> InlineKeyboardMarkup | None:
109
+ if lst := synopts[typ]:
110
+ if isinstance(lst, list):
111
+ kb = [[InlineKeyboardButton(text=n, callback_data=f"st:{typ.name}:{i}")] for i, n in enumerate(lst)]
112
+ elif isclass(lst) and issubclass(lst, IntEnum):
113
+ kb = [[InlineKeyboardButton(text=i.name, callback_data=f"st:{typ.name}:{i.value}")] for i in lst]
114
+ else:
115
+ kb = [[InlineKeyboardButton(text=n, callback_data=f"st:{typ.name}:{i}")] for i, n in await lst(txt)]
116
+ return InlineKeyboardMarkup(inline_keyboard=kb)
117
+ else:
118
+ return lst
xync_bot/routers/main.py CHANGED
@@ -6,7 +6,7 @@ from aiogram.exceptions import TelegramBadRequest
6
6
  from aiogram.filters import CommandStart, CommandObject, ChatMemberUpdatedFilter, JOIN_TRANSITION, LEAVE_TRANSITION
7
7
  from aiogram.filters.callback_data import CallbackData
8
8
  from aiogram.types import (
9
- User as TgUser,
9
+ User,
10
10
  ChatMemberUpdated,
11
11
  Message,
12
12
  InlineKeyboardMarkup,
@@ -15,12 +15,11 @@ from aiogram.types import (
15
15
  WebAppInfo,
16
16
  )
17
17
  from aiogram.utils.deep_linking import create_start_link
18
- from xync_schema.models import User, Order, Msg, Forum
18
+ from xync_schema import models
19
19
 
20
- from xync_bot.routers import user_upsert
21
20
  from xync_bot.shared import NavCallbackData
22
21
 
23
- main = Router()
22
+ mr = Router()
24
23
 
25
24
 
26
25
  class RrCallbackData(CallbackData, prefix="reg_res"): # registration response
@@ -38,19 +37,19 @@ home_btns = InlineKeyboardMarkup(
38
37
  )
39
38
 
40
39
 
41
- @main.message(CommandStart(deep_link=True, deep_link_encoded=True))
40
+ @mr.message(CommandStart(deep_link=True, deep_link_encoded=True))
42
41
  async def start_handler(msg: Message, command: CommandObject):
43
- me: TgUser = msg.from_user
42
+ me: User = msg.from_user
44
43
  ref_id: int = command.args.isnumeric() and int(command.args)
45
- user = await User.get_or_none(id=me.id, blocked=False)
44
+ user = await models.User.get_or_none(id=me.id, blocked=False)
46
45
  rm = None
47
46
  logging.info(msg, {"src": "start"})
48
47
  if user:
49
48
  rs, rm = f"{me.full_name}, you have registered already😉", home_btns
50
- elif not (ref := await User.get_or_none(id=ref_id)):
49
+ elif not (ref := await models.User.get_or_none(id=ref_id)):
51
50
  rs = f"No registered user #{ref_id}😬"
52
51
  else: # new user created
53
- user, cr = await user_upsert(me, False)
52
+ user, cr = await models.User.tg2in(me, False)
54
53
  await user.update_from_dict({"ref": ref}).save()
55
54
  approve_btns = InlineKeyboardMarkup(
56
55
  inline_keyboard=[
@@ -67,9 +66,9 @@ async def start_handler(msg: Message, command: CommandObject):
67
66
  return await msg.answer(rs, reply_markup=rm)
68
67
 
69
68
 
70
- @main.callback_query(RrCallbackData.filter())
69
+ @mr.callback_query(RrCallbackData.filter())
71
70
  async def phrases_input_request(cb: CallbackQuery, callback_data: RrCallbackData) -> None:
72
- protege = await User[callback_data.to]
71
+ protege = await models.User[callback_data.to]
73
72
  if callback_data.res:
74
73
  # protege.status = UserStatus.RESTRICTED
75
74
  await protege.save()
@@ -84,17 +83,17 @@ async def phrases_input_request(cb: CallbackQuery, callback_data: RrCallbackData
84
83
  await cb.message.edit_text(rs)
85
84
 
86
85
 
87
- @main.message(CommandStart(deep_link=True)) # attempt to reg by fake link
86
+ @mr.message(CommandStart(deep_link=True)) # attempt to reg by fake link
88
87
  async def fraud_handler(msg: Message):
89
88
  logging.warning(f"Start: {msg.from_user.id}. Msg: {msg}")
90
89
  # todo: alert to admins! Fraud attempt!
91
90
  await msg.answer("🤔")
92
91
 
93
92
 
94
- @main.message(CommandStart())
93
+ @mr.message(CommandStart())
95
94
  async def start_no_ref_handler(msg: Message):
96
95
  me = msg.from_user
97
- user, cr = await user_upsert(me, False)
96
+ user, cr = await models.User.tg2in(me, False)
98
97
  rr = "сначала вы должны найти поручителя, и перейти по его реферальной ссылке.\nhttps://telegra.ph/XyncNet-02-13"
99
98
  if cr: # has ref and created now
100
99
  await msg.answer(f"Здравствуйте {me.full_name}, что бы использовать возможности нашей сети, {rr}")
@@ -104,10 +103,10 @@ async def start_no_ref_handler(msg: Message):
104
103
  await msg.answer(f"{me.full_name}, не балуйтесь, вы и так уже активный участник👌🏼", reply_markup=home_btns)
105
104
 
106
105
 
107
- @main.callback_query(NavCallbackData.filter(F.to == "ref_link"))
106
+ @mr.callback_query(NavCallbackData.filter(F.to == "ref_link"))
108
107
  async def ref_link_handler(cbq: CallbackQuery):
109
108
  me = cbq.from_user
110
- if not (u := await User.get_or_none(id=me.id, blocked=False).prefetch_related("ref")):
109
+ if not (u := await models.User.get_or_none(id=me.id, blocked=False).prefetch_related("ref")):
111
110
  return await cbq.answer(f"{me.full_name}, сначала сами получите одобрение поручителя😉")
112
111
  link = await create_start_link(cbq.bot, str(u.id), encode=True)
113
112
  logging.info(f"Start: {me.id}. Msg: {cbq}")
@@ -119,36 +118,36 @@ async def ref_link_handler(cbq: CallbackQuery):
119
118
  await cbq.answer("Wait for your protege request..")
120
119
 
121
120
 
122
- @main.my_chat_member(F.chat.type == "private") # my_chat_member is fired on add bot to any chat. filter for preventing
121
+ @mr.my_chat_member(F.chat.type == "private") # my_chat_member is fired on add bot to any chat. filter for preventing
123
122
  async def my_user_set_status(my_chat_member: ChatMemberUpdated):
124
123
  logging.info({"my_chat_member": my_chat_member.model_dump(exclude_none=True)})
125
- u: TgUser = my_chat_member.from_user
124
+ u: User = my_chat_member.from_user
126
125
  blocked = my_chat_member.new_chat_member.status in ("left", "kicked")
127
- await user_upsert(u, blocked)
126
+ await models.User.tg2in(u, blocked)
128
127
 
129
128
 
130
- @main.my_chat_member()
129
+ @mr.my_chat_member()
131
130
  async def user_set_status(my_chat_member: ChatMemberUpdated):
132
131
  if my_chat_member.new_chat_member.user.username == "XyncNetBot": # удалена группа где бот был добавлен админом
133
- if forum := await Forum.get_or_none(id=my_chat_member.chat.id):
132
+ if forum := await models.Forum.get_or_none(id=my_chat_member.chat.id):
134
133
  await forum.delete()
135
134
  res = f"I {my_chat_member.new_chat_member.status} from {my_chat_member.chat.id}:{my_chat_member.chat.title}"
136
135
  return logging.info(res)
137
136
  logging.info({"my_chat_member": my_chat_member.model_dump(exclude_none=True)})
138
- u: TgUser = my_chat_member.from_user
137
+ u: User = my_chat_member.from_user
139
138
  blocked = my_chat_member.new_chat_member.status in ("left", "kicked")
140
139
  if blocked:
141
- if forum := await Forum.get_or_none(id=my_chat_member.chat.id, user_id=u.id):
140
+ if forum := await models.Forum.get_or_none(id=my_chat_member.chat.id, user_id=u.id):
142
141
  if forum.joined:
143
142
  forum.joined = False
144
143
  await forum.save()
145
- await user_upsert(u, blocked)
144
+ return await models.User.tg2in(u, blocked)
146
145
 
147
146
 
148
- @main.chat_member(ChatMemberUpdatedFilter(LEAVE_TRANSITION)) # юзер покинул группу Ордеров
147
+ @mr.chat_member(ChatMemberUpdatedFilter(LEAVE_TRANSITION)) # юзер покинул группу Ордеров
149
148
  async def on_user_leave(member: ChatMemberUpdated):
150
149
  logging.info({"user_leave": member.model_dump(exclude_none=True)})
151
- if forum := await Forum[member.chat.id]:
150
+ if forum := await models.Forum[member.chat.id]:
152
151
  if forum.joined:
153
152
  forum.joined = False
154
153
  await forum.save()
@@ -156,10 +155,10 @@ async def on_user_leave(member: ChatMemberUpdated):
156
155
  return await member.bot.send_message(member.new_chat_member.user.id, resp)
157
156
 
158
157
 
159
- @main.chat_member(ChatMemberUpdatedFilter(JOIN_TRANSITION)) # Юзер добавился в группу Ордеров
158
+ @mr.chat_member(ChatMemberUpdatedFilter(JOIN_TRANSITION)) # Юзер добавился в группу Ордеров
160
159
  async def on_user_join(member: ChatMemberUpdated, app_url: str):
161
160
  logging.info({"user_join": member.model_dump(exclude_none=True)})
162
- if forum := await Forum.get_or_none(id=member.chat.id):
161
+ if forum := await models.Forum.get_or_none(id=member.chat.id):
163
162
  if not forum.joined:
164
163
  forum.joined = True
165
164
  await forum.save()
@@ -170,26 +169,26 @@ async def on_user_join(member: ChatMemberUpdated, app_url: str):
170
169
  return await member.bot.send_message(member.new_chat_member.user.id, resp, reply_markup=rm)
171
170
 
172
171
 
173
- @main.message(F.is_topic_message)
172
+ @mr.message(F.is_topic_message)
174
173
  async def order_msg(msg: Message):
175
- sender = await User[msg.from_user.id]
174
+ sender = await models.User[msg.from_user.id]
176
175
  cid = msg.chat.shifted_id
177
176
  assert sender.forum == cid, "sender is not client"
178
- if order := await Order.get_or_none(taker__user_id=sender.id, taker_topic=msg.message_thread_id):
177
+ if order := await models.Order.get_or_none(taker__user_id=sender.id, taker_topic=msg.message_thread_id):
179
178
  is_taker = True
180
- elif order := await Order.get_or_none(ad__agent__user_id=sender.id, maker_topic=msg.message_thread_id):
179
+ elif order := await models.Order.get_or_none(ad__agent__user_id=sender.id, maker_topic=msg.message_thread_id):
181
180
  is_taker = False
182
181
  else:
183
182
  return await msg.answer("No such order")
184
183
  # raise Exception("No such order")
185
- receiver: User = await (order.ad.maker.user if is_taker else order.taker.user)
184
+ receiver: models.User = await (order.ad.maker.user if is_taker else order.taker.user)
186
185
  rcv_topic = order.taker_topic if is_taker else order.maker_topic
187
- await Msg.create(tgid=msg.message_id, txt=msg.text, order_id=order.id, receiver=receiver)
186
+ await models.Msg.create(tgid=msg.message_id, txt=msg.text, order_id=order.id, receiver=receiver)
188
187
  logging.info(msg, {"src": "order_msg"})
189
188
  return await msg.send_copy(receiver.forum, message_thread_id=rcv_topic)
190
189
 
191
190
 
192
- @main.message(
191
+ @mr.message(
193
192
  F.content_type.not_in(
194
193
  {
195
194
  ContentType.NEW_CHAT_MEMBERS,
@@ -211,7 +210,7 @@ async def del_cbq(msg: Message):
211
210
  logging.error({"NOT_DELETED": msg.model_dump(exclude_none=True)})
212
211
 
213
212
 
214
- @main.message()
213
+ @mr.message()
215
214
  async def all_rest(msg: Message):
216
215
  logging.warning(
217
216
  {
@@ -0,0 +1,133 @@
1
+ from aiogram import Router, F
2
+ from aiogram.filters import Command
3
+ from aiogram.types import Message
4
+ from xync_schema import models
5
+ from aiogram.types import ReplyKeyboardMarkup, KeyboardButton
6
+ from aiogram.utils.keyboard import InlineKeyboardMarkup, InlineKeyboardButton
7
+ from aiogram import types
8
+
9
+ from aiogram.fsm.state import State, StatesGroup
10
+ from aiogram.fsm.context import FSMContext
11
+
12
+ pay = Router()
13
+
14
+
15
+ class Cred(StatesGroup):
16
+ detail = State()
17
+ extra = State()
18
+
19
+
20
+ class Addr(StatesGroup):
21
+ name = State()
22
+
23
+
24
+ @pay.message(Command("pay"))
25
+ async def main(msg: Message):
26
+ start = ReplyKeyboardMarkup(
27
+ keyboard=[[KeyboardButton(text="крипта"), KeyboardButton(text="валюта (фиат)")]], resize_keyboard=True
28
+ )
29
+ await msg.answer("что нужно?", reply_markup=start)
30
+
31
+
32
+ @pay.message(F.text == "валюта (фиат)")
33
+ async def cur(msg: types.Message):
34
+ currencies = await models.Cur.all()
35
+ buttons = [[InlineKeyboardButton(text=cur.ticker, callback_data=f"cur_{cur.id}")] for cur in currencies]
36
+ keyboard = InlineKeyboardMarkup(inline_keyboard=buttons)
37
+ await msg.answer("Выберите валюту:", reply_markup=keyboard)
38
+
39
+
40
+ @pay.message(F.text == "крипта")
41
+ async def coin(msg: types.Message):
42
+ crypt = await models.Coin.all()
43
+ buttons = [[InlineKeyboardButton(text=coin.ticker, callback_data=f"coin_{coin.id}")] for coin in crypt]
44
+ keyboard = InlineKeyboardMarkup(inline_keyboard=buttons)
45
+ await msg.answer("Выберите крипту:", reply_markup=keyboard)
46
+
47
+
48
+ @pay.callback_query(F.data.startswith("coin_"))
49
+ async def coinex(query: types.CallbackQuery):
50
+ ticker = query.data.replace("coin_", "")
51
+ ex_id = await models.Coinex.filter(coin_id=ticker).values_list("ex_id", flat=True)
52
+ ex = await models.Ex.filter(id__in=ex_id).values_list("name", flat=True)
53
+ if not ex:
54
+ await query.message.answer("Такой биржи нет")
55
+ else:
56
+ buttons = [[InlineKeyboardButton(text=i, callback_data=f"ad_{i}")] for i in ex]
57
+ keyboard = InlineKeyboardMarkup(inline_keyboard=buttons)
58
+ await query.message.answer("Выберите биржу", reply_markup=keyboard)
59
+
60
+
61
+ @pay.callback_query(F.data.startswith("cur_"))
62
+ async def pm(query: types.CallbackQuery, state: FSMContext):
63
+ ticker = query.data.replace("cur_", "")
64
+ pmcur = await models.Pmcur.filter(cur_id=ticker).values_list("pm_id", flat=True)
65
+ pmex = await models.Pmex.filter(pm_id__in=pmcur).values_list("id", flat=True)
66
+ pm = await models.PmexBank.filter(pmex_id__in=pmex).values_list("name", flat=True)
67
+ if not pm:
68
+ await query.message.answer("Такой платежки нет")
69
+ else:
70
+ buttons = [[InlineKeyboardButton(text=i, callback_data=f"pm_{i}")] for i in pm]
71
+ keyboard = InlineKeyboardMarkup(inline_keyboard=buttons)
72
+ await query.message.answer("Выберите платежку", reply_markup=keyboard)
73
+
74
+
75
+ # 4) для cur
76
+ @pay.callback_query(F.data.startswith("pm_"))
77
+ async def cred(query: types.CallbackQuery, state: FSMContext):
78
+ name = query.data.replace("pm_", "")
79
+ await state.update_data(name=name)
80
+ pmex_id = await models.PmexBank.filter(name=name).values_list("pmex_id", flat=True)
81
+ pm_id = await models.Pmex.filter(id__in=pmex_id).values_list("pm_id", flat=True)
82
+ pmcur = await models.Pmcur.get(id__in=pm_id)
83
+ await state.update_data(pmcur_id=pmcur.id)
84
+ await query.message.answer("Введите реквизиты")
85
+ await state.set_state(Cred.detail)
86
+
87
+
88
+ @pay.message(Cred.detail)
89
+ async def cred_detail(msg: types.Message, state: FSMContext):
90
+ user_id = msg.from_user.id
91
+ # user_id = 193017646
92
+ person_id = await models.User.get(username_id=user_id)
93
+ await state.update_data(person_id=person_id.person_id)
94
+ await state.update_data(detail=msg.text)
95
+ await msg.answer("Введите доп информацию")
96
+ await state.set_state(Cred.extra)
97
+
98
+
99
+ @pay.message(Cred.extra)
100
+ async def create_cred(msg: types.Message, state: FSMContext):
101
+ await state.update_data(extra=msg.text)
102
+ data = await state.get_data()
103
+ await state.clear()
104
+ # print(data)
105
+ data_create = {
106
+ "detail": data["detail"],
107
+ "name": data["name"],
108
+ "extra": data["extra"],
109
+ "person_id": data["person_id"],
110
+ "pmcur_id": data["pmcur_id"],
111
+ }
112
+ await models.Cred.create(**data_create)
113
+
114
+
115
+ # 4) для coin
116
+ @pay.callback_query(F.data.startswith("ad_"))
117
+ async def addr(query: types.CallbackQuery, state: FSMContext):
118
+ name = query.data.replace("ad_", "")
119
+ ex = await models.Ex.filter(name=name).values_list("id", flat=True)
120
+ await state.update_data(ex_id=ex)
121
+ await query.message.answer("Введите имя")
122
+ await state.set_state(Addr.name)
123
+
124
+
125
+ @pay.message(Addr.name)
126
+ async def addr_name(msg: types.Message, state: FSMContext):
127
+ # user_id = msg.from_user.id
128
+ user_id = 193017646
129
+ person_id = await models.User.get(username_id=user_id)
130
+ await state.update_data(person_id=person_id.person_id)
131
+ await state.update_data(name=msg.text)
132
+ await state.get_data()
133
+ await state.clear()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xync-bot
3
- Version: 0.3.7.dev1
3
+ Version: 0.3.7.dev4
4
4
  Summary: Telegram bot with web app for xync net
5
5
  Author-email: Artemiev <mixartemev@gmail.com>
6
6
  License-Expression: GPL-3.0-or-later
@@ -8,6 +8,8 @@ Project-URL: Homepage, https://gitlab.com/xync/back/tg-bot
8
8
  Project-URL: Repository, https://gitlab.com/xync/back/tg-bot
9
9
  Keywords: aiogram,cyrtranslit,xync-net
10
10
  Requires-Python: >=3.12
11
+ Requires-Dist: cyrtranslit
12
+ Requires-Dist: xn-auth
11
13
  Requires-Dist: xync-schema
12
14
  Provides-Extra: dev
13
15
  Requires-Dist: PGram; extra == "dev"
@@ -0,0 +1,17 @@
1
+ xync_bot/__init__.py,sha256=wiZpB8Bv4jjaHeGS_yt9HKtuLTHwx4nCsCgcrMesCFE,586
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=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ xync_bot/routers/main.py,sha256=FumWa48ORhV77Df6NbEosHfgmFIe_Y2ci6IkJCvU4Zs,9535
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=It4djVO8AxXL1I76buRz8yYF12dsjXaa4WNtPdb7CFc,4333
12
+ xync_bot/routers/cond/func.py,sha256=m0NWDKunbqDJQmhv_5UnpjxjRzn78GFG94ThOFLVlQo,4720
13
+ xync_bot/routers/pay/main.py,sha256=5swOvvKF2XA2UAwHewdidMoMONV4acTwR0mPyzA0ezA,5116
14
+ xync_bot-0.3.7.dev4.dist-info/METADATA,sha256=4T0s0NFTh9QNuQ3JpSLKarYsXY-OZjN0vTjGrkNbeQI,750
15
+ xync_bot-0.3.7.dev4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
+ xync_bot-0.3.7.dev4.dist-info/top_level.txt,sha256=O2IjMc1ryAf0rwIXWohSNT5Kzcs9johgKRDz8lCC0rs,9
17
+ xync_bot-0.3.7.dev4.dist-info/RECORD,,
File without changes
@@ -1,16 +0,0 @@
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,,