xync-bot 0.3.24.dev12__py3-none-any.whl → 0.3.26__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/__main__.py ADDED
@@ -0,0 +1,37 @@
1
+ import logging
2
+ from asyncio import run
3
+
4
+ from PGram import Bot
5
+ from aiogram.client.default import DefaultBotProperties
6
+ from aiogram.enums import UpdateType
7
+ from x_model import init_db
8
+
9
+ from xync_bot.store import Store
10
+ from xync_bot.routers.main.handler import mr
11
+ from xync_bot.routers.cond import cr
12
+ from xync_bot.routers.pay.handler import pr
13
+ from xync_bot.routers import last
14
+ from xync_bot.routers.send import sd
15
+
16
+ au = [
17
+ UpdateType.MESSAGE,
18
+ UpdateType.CALLBACK_QUERY,
19
+ UpdateType.CHAT_MEMBER,
20
+ UpdateType.MY_CHAT_MEMBER,
21
+ ] # , UpdateType.CHAT_JOIN_REQUEST
22
+ bot = Bot([sd, cr, pr, mr, last], Store(), au, default=DefaultBotProperties(parse_mode="HTML"))
23
+
24
+ if __name__ == "__main__":
25
+ from xync_bot.loader import TOKEN, TORM
26
+
27
+ logging.basicConfig(level=logging.INFO)
28
+
29
+ async def main() -> None:
30
+ cn = await init_db(TORM)
31
+ bot.dp.workflow_data["store"].glob = await Store.Global() # todo: refact store loading
32
+ await bot.start(
33
+ TOKEN,
34
+ cn,
35
+ )
36
+
37
+ run(main())
@@ -0,0 +1,41 @@
1
+ import logging
2
+
3
+ from aiogram import Router, F
4
+ from aiogram.enums import ContentType
5
+ from aiogram.exceptions import TelegramBadRequest
6
+ from aiogram.types import Message
7
+
8
+ last = Router(name="last")
9
+
10
+
11
+ @last.message(
12
+ F.content_type.not_in(
13
+ {
14
+ ContentType.NEW_CHAT_MEMBERS,
15
+ # ContentType.LEFT_CHAT_MEMBER,
16
+ # ContentType.SUPERGROUP_CHAT_CREATED,
17
+ # ContentType.NEW_CHAT_PHOTO,
18
+ # ContentType.FORUM_TOPIC_CREATED,
19
+ # ContentType.FORUM_TOPIC_EDITED,
20
+ ContentType.FORUM_TOPIC_CLOSED,
21
+ # ContentType.GENERAL_FORUM_TOPIC_HIDDEN, # deletable
22
+ }
23
+ )
24
+ )
25
+ async def del_cbq(msg: Message):
26
+ try:
27
+ await msg.delete()
28
+ logging.info({"DELETED": msg.model_dump(exclude_none=True)})
29
+ except TelegramBadRequest:
30
+ logging.error({"NOT_DELETED": msg.model_dump(exclude_none=True)})
31
+
32
+
33
+ @last.message()
34
+ async def all_rest(msg: Message):
35
+ logging.warning(
36
+ {
37
+ "NO_HANDLED": msg.model_dump(
38
+ exclude_none=True,
39
+ )
40
+ }
41
+ )
@@ -8,7 +8,7 @@ from xync_schema.enums import SynonymType
8
8
 
9
9
  from xync_bot.routers.cond.func import wrap_cond, get_val, btns, rkm, ikm, SynTypeCd, CondCd
10
10
 
11
- cr = Router()
11
+ cr = Router(name="cond")
12
12
 
13
13
 
14
14
  @cr.message(Command("cond"))
@@ -89,9 +89,3 @@ async def got_action(cbq: CallbackQuery, callback_data: CondCd, state: FSMContex
89
89
  await (await state.get_value("cmsg")).delete()
90
90
  await show_cond(cbq.message, cond)
91
91
  return await cbq.answer(callback_data.act)
92
-
93
-
94
- @cr.message()
95
- async def unknown(msg: Message):
96
- # user = await User.get(username_id=msg.from_user.id)
97
- await msg.delete()
File without changes
@@ -1,8 +1,6 @@
1
1
  import logging
2
2
 
3
3
  from aiogram import Router, F
4
- from aiogram.enums import ContentType
5
- from aiogram.exceptions import TelegramBadRequest
6
4
  from aiogram.filters import CommandStart, CommandObject, ChatMemberUpdatedFilter, JOIN_TRANSITION, LEAVE_TRANSITION
7
5
  from aiogram.filters.callback_data import CallbackData
8
6
  from aiogram.types import (
@@ -18,8 +16,9 @@ from aiogram.utils.deep_linking import create_start_link
18
16
  from xync_schema import models
19
17
 
20
18
  from xync_bot.shared import NavCallbackData
19
+ from xync_bot.store import Store
21
20
 
22
- mr = Router()
21
+ mr = Router(name="main")
23
22
 
24
23
 
25
24
  class RrCallbackData(CallbackData, prefix="reg_res"): # registration response
@@ -30,6 +29,7 @@ class RrCallbackData(CallbackData, prefix="reg_res"): # registration response
30
29
  home_btns = InlineKeyboardMarkup(
31
30
  inline_keyboard=[
32
31
  [
32
+ InlineKeyboardButton(text="Transfer", callback_data=NavCallbackData(to="transfer").pack()),
33
33
  InlineKeyboardButton(text="Invite", callback_data=NavCallbackData(to="ref_link").pack()),
34
34
  InlineKeyboardButton(text="Get VPN", callback_data=NavCallbackData(to="get_vpn").pack()),
35
35
  ]
@@ -41,7 +41,7 @@ home_btns = InlineKeyboardMarkup(
41
41
  async def start_handler(msg: Message, command: CommandObject):
42
42
  me: User = msg.from_user
43
43
  ref_id: int = command.args.isnumeric() and int(command.args)
44
- user = await models.User.get_or_none(id=me.id, blocked=False)
44
+ user = await models.User.get(username_id=me.id, blocked=False)
45
45
  rm = None
46
46
  logging.info(msg, {"src": "start"})
47
47
  if user:
@@ -66,6 +66,27 @@ async def start_handler(msg: Message, command: CommandObject):
66
66
  return await msg.answer(rs, reply_markup=rm)
67
67
 
68
68
 
69
+ @mr.message(CommandStart(deep_link=True)) # attempt to reg by fake link
70
+ async def fraud_handler(msg: Message):
71
+ logging.warning(f"Start: {msg.from_user.id}. Msg: {msg}")
72
+ # todo: alert to admins! Fraud attempt!
73
+ await msg.answer("🤔")
74
+
75
+
76
+ @mr.message(CommandStart()) # обычный /start
77
+ async def home(msg: Message, store: Store):
78
+ me = msg.from_user
79
+ user, is_new = await models.User.tg_upsert(me, False)
80
+
81
+ rr = "сначала вы должны найти поручителя, и перейти по его реферальной ссылке.\nhttps://telegra.ph/XyncNet-02-13"
82
+ if is_new: # has ref and created now
83
+ await msg.answer(f"Здравствуйте {me.full_name}, что бы использовать возможности нашей сети, {rr}")
84
+ elif not user.ref_id:
85
+ await msg.answer(rr.capitalize())
86
+ else:
87
+ await msg.answer(f"{me.full_name}, не балуйтесь, вы и так уже активный участник👌🏼", reply_markup=home_btns)
88
+
89
+
69
90
  @mr.callback_query(RrCallbackData.filter())
70
91
  async def phrases_input_request(cb: CallbackQuery, callback_data: RrCallbackData) -> None:
71
92
  protege = await models.User[callback_data.to]
@@ -83,27 +104,7 @@ async def phrases_input_request(cb: CallbackQuery, callback_data: RrCallbackData
83
104
  await cb.message.edit_text(rs)
84
105
 
85
106
 
86
- @mr.message(CommandStart(deep_link=True)) # attempt to reg by fake link
87
- async def fraud_handler(msg: Message):
88
- logging.warning(f"Start: {msg.from_user.id}. Msg: {msg}")
89
- # todo: alert to admins! Fraud attempt!
90
- await msg.answer("🤔")
91
-
92
-
93
- @mr.message(CommandStart())
94
- async def start_no_ref_handler(msg: Message):
95
- me = msg.from_user
96
- user, cr = await models.User.tg2in(me, False)
97
- rr = "сначала вы должны найти поручителя, и перейти по его реферальной ссылке.\nhttps://telegra.ph/XyncNet-02-13"
98
- if cr: # has ref and created now
99
- await msg.answer(f"Здравствуйте {me.full_name}, что бы использовать возможности нашей сети, {rr}")
100
- elif not user.ref_id:
101
- await msg.answer(rr.capitalize())
102
- else:
103
- await msg.answer(f"{me.full_name}, не балуйтесь, вы и так уже активный участник👌🏼", reply_markup=home_btns)
104
-
105
-
106
- @mr.callback_query(NavCallbackData.filter(F.to == "ref_link"))
107
+ @mr.callback_query(NavCallbackData.filter(F.to.__eq__("ref_link")))
107
108
  async def ref_link_handler(cbq: CallbackQuery):
108
109
  me = cbq.from_user
109
110
  if not (u := await models.User.get_or_none(id=me.id, blocked=False).prefetch_related("ref")):
@@ -118,7 +119,7 @@ async def ref_link_handler(cbq: CallbackQuery):
118
119
  await cbq.answer("Wait for your protege request..")
119
120
 
120
121
 
121
- @mr.my_chat_member(F.chat.type == "private") # my_chat_member is fired on add bot to any chat. filter for preventing
122
+ @mr.my_chat_member(F.chat.type == "private") # my_chat_member is fired on adding bot to any chat. filter for preventing
122
123
  async def my_user_set_status(my_chat_member: ChatMemberUpdated):
123
124
  logging.info({"my_chat_member": my_chat_member.model_dump(exclude_none=True)})
124
125
  u: User = my_chat_member.from_user
@@ -128,7 +129,7 @@ async def my_user_set_status(my_chat_member: ChatMemberUpdated):
128
129
 
129
130
  @mr.my_chat_member()
130
131
  async def user_set_status(my_chat_member: ChatMemberUpdated):
131
- if my_chat_member.new_chat_member.user.username == "XyncNetBot": # удалена группа где бот был добавлен админом
132
+ if my_chat_member.new_chat_member.user.username == "XyncNetBot": # удалена группа, где бот был добавлен админом
132
133
  if forum := await models.Forum.get_or_none(id=my_chat_member.chat.id):
133
134
  await forum.delete()
134
135
  res = f"I {my_chat_member.new_chat_member.status} from {my_chat_member.chat.id}:{my_chat_member.chat.title}"
@@ -186,36 +187,3 @@ async def order_msg(msg: Message):
186
187
  await models.Msg.create(tgid=msg.message_id, txt=msg.text, order_id=order.id, receiver=receiver)
187
188
  logging.info(msg, {"src": "order_msg"})
188
189
  return await msg.send_copy(receiver.forum, message_thread_id=rcv_topic)
189
-
190
-
191
- @mr.message(
192
- F.content_type.not_in(
193
- {
194
- ContentType.NEW_CHAT_MEMBERS,
195
- # ContentType.LEFT_CHAT_MEMBER,
196
- # ContentType.SUPERGROUP_CHAT_CREATED,
197
- # ContentType.NEW_CHAT_PHOTO,
198
- # ContentType.FORUM_TOPIC_CREATED,
199
- # ContentType.FORUM_TOPIC_EDITED,
200
- ContentType.FORUM_TOPIC_CLOSED,
201
- # ContentType.GENERAL_FORUM_TOPIC_HIDDEN, # deletable
202
- }
203
- )
204
- )
205
- async def del_cbq(msg: Message):
206
- try:
207
- await msg.delete()
208
- logging.info({"DELETED": msg.model_dump(exclude_none=True)})
209
- except TelegramBadRequest:
210
- logging.error({"NOT_DELETED": msg.model_dump(exclude_none=True)})
211
-
212
-
213
- @mr.message()
214
- async def all_rest(msg: Message):
215
- logging.warning(
216
- {
217
- "NO_HANDLED": msg.model_dump(
218
- exclude_none=True,
219
- )
220
- }
221
- )
@@ -1,4 +1,3 @@
1
- import logging
2
1
  from asyncio import gather
3
2
  from enum import IntEnum
4
3
 
@@ -6,8 +5,6 @@ from aiogram.exceptions import TelegramBadRequest
6
5
  from aiogram.fsm.state import StatesGroup, State
7
6
  from aiogram.types import Message, InlineKeyboardMarkup
8
7
  from pyrogram.types import CallbackQuery
9
- from tortoise.functions import Min
10
- from x_auth.enums import Role
11
8
  from x_model.func import ArrayAgg
12
9
  from xync_schema import models
13
10
 
@@ -60,107 +57,6 @@ class PayStep(IntEnum):
60
57
  pending_receive = 19 # Ожидание поступления (если мы получаем фиат)
61
58
 
62
59
 
63
- flags = {
64
- "RUB": "🇷🇺",
65
- "THB": "🇹🇭",
66
- "IDR": "🇮🇩",
67
- "TRY": "🇹🇷",
68
- "GEL": "🇬🇪",
69
- "VND": "🇻🇳",
70
- "AED": "🇦🇪",
71
- "AMD": "🇦🇲",
72
- "AZN": "🇦🇿",
73
- "CNY": "🇨🇳",
74
- "EUR": "🇪🇺",
75
- "HKD": "🇭🇰",
76
- "INR": "🇮🇳",
77
- "PHP": "🇵🇭",
78
- "USD": "🇺🇸",
79
- }
80
-
81
-
82
- class SingleStore(type):
83
- _store = None
84
-
85
- async def __call__(cls):
86
- if not cls._store:
87
- cls._store = super(SingleStore, cls).__call__()
88
- cls._store.coins = {k: v for k, v in await models.Coin.all().order_by("ticker").values_list("id", "ticker")}
89
- curs = {c.id: c for c in await models.Cur.filter(ticker__in=flags.keys()).order_by("ticker")}
90
- cls._store.curs = curs
91
- cls._store.exs = {k: v for k, v in await models.Ex.all().values_list("id", "name")}
92
- cls._store.pmcurs = {
93
- k: v
94
- for k, v in await models.Pmex.filter(pm__pmcurs__cur_id__in=cls._store.curs.keys())
95
- .annotate(sname=Min("name"))
96
- .group_by("pm__pmcurs__id")
97
- .values_list("pm__pmcurs__id", "sname")
98
- }
99
- cls._store.coinexs = {
100
- c.id: [ex.ex_id for ex in c.coinexs] for c in await models.Coin.all().prefetch_related("coinexs")
101
- }
102
- cls._store.curpms = {
103
- cur_id: ids
104
- for cur_id, ids in await models.Pmcur.filter(cur_id__in=curs.keys())
105
- .annotate(ids=ArrayAgg("id"))
106
- .group_by("cur_id")
107
- .values_list("cur_id", "ids")
108
- }
109
- cls._store.curpms = {
110
- cur_id: ids
111
- for cur_id, ids in await models.Pmcur.filter(cur_id__in=curs.keys())
112
- .annotate(ids=ArrayAgg("id"))
113
- .group_by("cur_id")
114
- .values_list("cur_id", "ids")
115
- }
116
-
117
- return cls._store
118
-
119
-
120
- class Store:
121
- class Global(metaclass=SingleStore):
122
- coins: dict[int, str] # id:ticker
123
- curs: dict[int, models.Cur] # id:Cur
124
- exs: dict[int, str] # id:name
125
- coinexs: dict[int, list[int]] # id:[ex_ids]
126
- pmcurs: dict[int, str] # pmcur_id:name
127
- curpms: dict[int, list[int]] # id:[pmcur_ids]
128
-
129
- class Permanent:
130
- msg_id: int = None
131
- user: models.User = None
132
- actors: dict[int, int] = None # key=ex_id
133
- creds: dict[int, models.Cred] = None # key=cred_id
134
- cur_creds: dict[int, list[int]] = None # pmcur_id:[cred_ids]
135
-
136
- class Current:
137
- is_target: bool = True
138
- is_fiat: bool = None
139
- msg_to_del: Message = None
140
-
141
- class Payment:
142
- t_cur_id: int = None
143
- s_cur_id: int = None
144
- t_coin_id: int = None
145
- s_coin_id: int = None
146
- t_pmcur_id: int = None
147
- s_pmcur_id: int = None
148
- t_ex_id: int = None
149
- s_ex_id: int = None
150
- amount: int | float = None
151
- ppo: int = 1
152
- addr_id: int = None
153
- cred_dtl: str = None
154
- cred_id: int = None
155
- urg: int = 5
156
- pr_id: int = None
157
-
158
- glob: Global
159
- perm: Permanent = Permanent()
160
- pay: Payment = Payment()
161
- curr: Current = Current()
162
-
163
-
164
60
  async def fill_creds(person_id: int) -> tuple[dict[int, models.Cred], dict[int, list[int]]]:
165
61
  cq = models.Cred.filter(person_id=person_id)
166
62
  creds = {c.id: c for c in await cq}
@@ -207,73 +103,6 @@ async def edt(msg: Message, txt: str, rm: InlineKeyboardMarkup):
207
103
  print(msg.bot.store.perm.msg_id, e)
208
104
 
209
105
 
210
- async def xync_have_coin_amount(store: Store) -> bool:
211
- assets = await models.Asset.filter(
212
- addr__coin_id=store.pay.t_coin_id, addr__ex_id=store.pay.t_ex_id, addr__actor__user__role__in=Role.ADMIN
213
- )
214
- return store.pay.amount <= sum(a.free for a in assets)
215
-
216
-
217
- async def client_have_coin_amount(store: Store) -> bool:
218
- assets = await models.Asset.filter(addr__coin_id=store.pay.t_coin_id, addr__actor_id__in=store.perm.actors.values())
219
- return store.pay.amount <= sum(a.free for a in assets)
220
-
221
-
222
- async def need_ppo(store: Store):
223
- cur_id = getattr(store.pay, ("t" if store.curr.is_target else "s") + "_cur_id")
224
- usd_amount = store.pay.amount * store.glob.curs[cur_id].rate
225
- if usd_amount < 50:
226
- return 0
227
- elif usd_amount > 100:
228
- return 2
229
- else:
230
- return 1
231
-
232
-
233
- async def client_target_repr(store: Store) -> tuple[models.Addr | models.Cred, str]:
234
- if store.pay.t_ex_id:
235
- addr_to = (
236
- await models.Addr.filter(
237
- actor__ex_id=store.pay.t_ex_id, coin_id=store.pay.t_coin_id, actor__user=store.perm.user
238
- )
239
- .prefetch_related("actor")
240
- .first()
241
- )
242
- ex, coin = store.glob.exs[store.pay.s_ex_id], store.glob.coins[store.pay.s_coin_id]
243
- if not addr_to:
244
- logging.error(f"No {coin} addr in {ex} for user: {store.perm.user.username_id}")
245
- return addr_to, f"{coin} на {ex} по id: `{addr_to.actor.exid}`"
246
- # иначе: реквизиты для фиата
247
- cur, pm = store.glob.curs[store.pay.t_cur_id], store.glob.pmcurs[store.pay.t_pmcur_id]
248
- cred = store.perm.creds[store.pay.cred_id]
249
- return cred, f"{cur.ticker} на {pm} по номеру: {cred.repr()}"
250
-
251
-
252
- async def get_merch_target(store: Store) -> tuple[models.Addr | models.Cred, str]:
253
- if store.pay.s_ex_id:
254
- addr_in = (
255
- await models.Addr.filter(
256
- actor__ex_id=store.pay.s_ex_id, coin_id=store.pay.s_coin_id, actor__user__role__gte=Role.ADMIN
257
- )
258
- .prefetch_related("actor")
259
- .first()
260
- )
261
- ex, coin = store.glob.exs[store.pay.s_ex_id], store.glob.coins[store.pay.s_coin_id]
262
- if not addr_in:
263
- logging.error(f"No {coin} addr in {ex}")
264
- return addr_in, f"{coin} на {ex} по id: `{addr_in.actor.exid}`"
265
- # иначе: реквизиты для фиатной оплаты
266
- s_pmcur = await models.Pmcur.get(id=store.pay.s_pmcur_id).prefetch_related("pm__grp")
267
- cred = await models.Cred.filter(
268
- **({"pmcur__pm__grp": s_pmcur.pm.grp} if s_pmcur.pm.grp else {"pmcur_id": store.pay.s_pmcur_id}),
269
- person__user__role__gte=Role.ADMIN,
270
- ).first() # todo: order by fiat.target-fiat.amount
271
- cur, pm = store.glob.curs[store.pay.s_cur_id], store.glob.pmcurs[store.pay.s_pmcur_id]
272
- if not cred:
273
- logging.error(f"No {cur.ticker} cred for {pm}")
274
- return cred, f"{cur.ticker} на {pm} по номеру: {cred.repr()}"
275
-
276
-
277
106
  def fmt_sec(sec: int):
278
107
  days = sec // (24 * 3600)
279
108
  sec %= 24 * 3600