xync-bot 0.2.10__py3-none-any.whl → 0.3.2__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
@@ -1,39 +0,0 @@
1
- from aiogram.client.default import DefaultBotProperties
2
- from aiogram.types import MenuButtonWebApp, WebAppInfo
3
- import logging
4
- from os import getenv as env
5
- from dotenv import load_dotenv
6
- from aiogram import Bot, Dispatcher
7
- from tortoise.backends.asyncpg import AsyncpgDBClient
8
-
9
- from xync_bot.handlers import main, vpn
10
-
11
- load_dotenv()
12
-
13
- logging.basicConfig(filemode='a', level=logging.DEBUG)
14
-
15
- bot = Bot(token=env('TOKEN'), default=DefaultBotProperties(parse_mode='Markdown'))
16
- dp = Dispatcher(bot=bot)
17
-
18
-
19
- async def on_startup(wh_url: str, twa_url: str, cn: AsyncpgDBClient, mbt: str = 'Go!'):
20
- """ SET DEISPATCHER GLOBAL WORKFLOW DATA FOR DB Connection """
21
- dp['dbc'] = cn
22
- """ WEBHOOK SETUP """
23
- webhook_info = await bot.get_webhook_info()
24
- if webhook_info.url != wh_url:
25
- await bot.set_webhook(url=wh_url, drop_pending_updates=True)
26
- """ WEBAPP URL SETUP IN MENU """
27
- await bot.set_chat_menu_button(menu_button=MenuButtonWebApp(text=mbt, web_app=WebAppInfo(url=twa_url)))
28
-
29
-
30
- async def on_shutdown():
31
- """ CLOSE BOT SESSION """
32
- await bot.delete_webhook(drop_pending_updates=True)
33
- await bot.session.close()
34
-
35
-
36
- dp.startup.register(on_startup)
37
- dp.shutdown.register(on_shutdown)
38
-
39
- dp.include_routers(vpn, main)
@@ -1,2 +0,0 @@
1
- from xync_bot.handlers.vpn import vpn
2
- from xync_bot.handlers.main import main
xync_bot/handlers/main.py CHANGED
@@ -1,11 +1,25 @@
1
1
  import logging
2
+ from os import path
3
+
2
4
  from aiogram import Router, F
3
- from aiogram.filters import CommandStart, CommandObject
5
+ from aiogram.enums import ContentType
6
+ from aiogram.filters import CommandStart, CommandObject, IS_MEMBER, IS_NOT_MEMBER, ChatMemberUpdatedFilter
4
7
  from aiogram.filters.callback_data import CallbackData
5
- from aiogram.types import User as TgUser, ChatMemberUpdated, Message, InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery
8
+ from aiogram.types import (
9
+ User as TgUser,
10
+ ChatMemberUpdated,
11
+ Message,
12
+ InlineKeyboardMarkup,
13
+ InlineKeyboardButton,
14
+ CallbackQuery,
15
+ ChatJoinRequest,
16
+ WebAppInfo,
17
+ FSInputFile,
18
+ )
6
19
  from aiogram.utils.deep_linking import create_start_link
7
20
  from aiogram.utils.web_app import WebAppUser
8
- from xync_schema.models import User, UserStatus, Lang
21
+ from tg_auth import Lang
22
+ from xync_schema.models import User, UserStatus, Order, Msg, Forum
9
23
 
10
24
  from xync_bot.shared import NavCallbackData
11
25
 
@@ -18,10 +32,13 @@ class RrCallbackData(CallbackData, prefix="reg_res"): # registration response
18
32
 
19
33
 
20
34
  home_btns = InlineKeyboardMarkup(
21
- inline_keyboard=[[
22
- InlineKeyboardButton(text='Invite', callback_data=NavCallbackData(to='ref_link').pack()),
23
- InlineKeyboardButton(text='Get VPN', callback_data=NavCallbackData(to='get_vpn').pack()),
24
- ]])
35
+ inline_keyboard=[
36
+ [
37
+ InlineKeyboardButton(text="Invite", callback_data=NavCallbackData(to="ref_link").pack()),
38
+ InlineKeyboardButton(text="Get VPN", callback_data=NavCallbackData(to="get_vpn").pack()),
39
+ ]
40
+ ]
41
+ )
25
42
 
26
43
 
27
44
  @main.message(CommandStart(deep_link=True, deep_link_encoded=True))
@@ -31,19 +48,24 @@ async def start_handler(msg: Message, command: CommandObject):
31
48
  user = await User.get_or_none(id=me.id, status__gte=UserStatus.RESTRICTED)
32
49
  rm = None
33
50
  if user:
34
- rs, rm = f'{me.full_name}, you have registered already😉', home_btns
51
+ rs, rm = f"{me.full_name}, you have registered already😉", home_btns
35
52
  elif not (ref := await User.get_or_none(id=ref_id)):
36
- rs = f'No registered user #{ref_id}😬'
53
+ rs = f"No registered user #{ref_id}😬"
37
54
  else: # new user created
38
55
  user, cr = await user_upsert(me)
39
- await user.update_from_dict({'ref': ref}).save()
56
+ await user.update_from_dict({"ref": ref}).save()
40
57
  approve_btns = InlineKeyboardMarkup(
41
- inline_keyboard=[[
42
- InlineKeyboardButton(text='Отклонить', callback_data=RrCallbackData(to=user.id, res=False).pack()),
43
- InlineKeyboardButton(text='Одобрить', callback_data=RrCallbackData(to=user.id, res=True).pack())
44
- ]])
45
- await msg.bot.send_message(ref.id, f'{me.full_name} просит что б Вы взяли за него/ее ответственность', reply_markup=approve_btns)
46
- return await msg.answer(f'Please wait for @{ref.username} approving...')
58
+ inline_keyboard=[
59
+ [
60
+ InlineKeyboardButton(text="Отклонить", callback_data=RrCallbackData(to=user.id, res=False).pack()),
61
+ InlineKeyboardButton(text="Одобрить", callback_data=RrCallbackData(to=user.id, res=True).pack()),
62
+ ]
63
+ ]
64
+ )
65
+ await msg.bot.send_message(
66
+ ref.id, f"{me.full_name} просит что б Вы взяли за него/ее ответственность", reply_markup=approve_btns
67
+ )
68
+ return await msg.answer(f"Please wait for @{ref.username} approving...")
47
69
  return await msg.answer(rs, reply_markup=rm)
48
70
 
49
71
 
@@ -53,65 +75,162 @@ async def phrases_input_request(cb: CallbackQuery, callback_data: RrCallbackData
53
75
  if callback_data.res:
54
76
  # protege.status = UserStatus.RESTRICTED
55
77
  await protege.save()
56
- rs = f'{cb.from_user.full_name}, теперь Вы несете ответветвенность за {protege.username}'
78
+ rs = f"{cb.from_user.full_name}, теперь Вы несете ответветвенность за {protege.username}"
57
79
  else:
58
80
  rs = f'Вы отклонили запрос юзера "{protege.username}" на Вашу протекцию'
59
- res = {True: 'одобрил', False: 'отклонил'}
60
- txt = f'{cb.from_user.full_name} {res[callback_data.res]} вашу регистрацию'
61
- txt, rm = (f'Поздравляем! {txt}💥', home_btns) if callback_data.res else (f'К сожалению {txt}😢', None)
81
+ res = {True: "одобрил", False: "отклонил"}
82
+ txt = f"{cb.from_user.full_name} {res[callback_data.res]} вашу регистрацию"
83
+ txt, rm = (f"Поздравляем! {txt}💥", home_btns) if callback_data.res else (f"К сожалению {txt}😢", None)
62
84
  await cb.bot.send_message(protege.id, txt, reply_markup=rm)
63
- await cb.answer('👌🏼')
85
+ await cb.answer("👌🏼")
64
86
  await cb.message.edit_text(rs)
65
87
 
66
88
 
67
89
  @main.message(CommandStart(deep_link=True)) # attempt to reg by fake link
68
90
  async def fraud_handler(msg: Message):
69
- logging.info(f'Start: {msg.from_user.id}. Msg: {msg}')
91
+ logging.info(f"Start: {msg.from_user.id}. Msg: {msg}")
70
92
  # todo: alert to admins! Fraud attempt!
71
- await msg.answer('🤔')
93
+ await msg.answer("🤔")
72
94
 
73
95
 
74
96
  @main.message(CommandStart())
75
97
  async def start_no_ref_handler(msg: Message):
76
98
  me = msg.from_user
77
99
  user, cr = await user_upsert(me)
78
- rr = 'сначала вы должны найти поручителя, и перейти по его реферальной ссылке.\nhttps://telegra.ph/XyncNet-02-13'
100
+ rr = "сначала вы должны найти поручителя, и перейти по его реферальной ссылке.\nhttps://telegra.ph/XyncNet-02-13"
79
101
  if cr: # has ref and created now
80
- await msg.answer(f'Здравствуйте {me.full_name}, что бы использовать возможности нашей сети, {rr}')
102
+ await msg.answer(f"Здравствуйте {me.full_name}, что бы использовать возможности нашей сети, {rr}")
81
103
  elif not user.ref_id:
82
104
  await msg.answer(rr.capitalize())
83
105
  else:
84
- await msg.answer(f'{me.full_name}, не балуйтесь, вы и так уже активный участник👌🏼', reply_markup=home_btns)
106
+ await msg.answer(f"{me.full_name}, не балуйтесь, вы и так уже активный участник👌🏼", reply_markup=home_btns)
85
107
 
86
108
 
87
- @main.callback_query(NavCallbackData.filter(F.to == 'ref_link'))
109
+ @main.callback_query(NavCallbackData.filter(F.to == "ref_link"))
88
110
  async def ref_link_handler(cbq: CallbackQuery):
89
111
  me = cbq.from_user
90
- if not (u := await User.get_or_none(id=me.id, status__gt=UserStatus.RESTRICTED).prefetch_related('ref')):
112
+ if not (u := await User.get_or_none(id=me.id, status__gt=UserStatus.RESTRICTED).prefetch_related("ref")):
91
113
  return await cbq.answer(f"{me.full_name}, сначала сами получите одобрение поручителя😉")
92
114
  link = await create_start_link(cbq.bot, str(u.id), encode=True)
93
- logging.info(f'Start: {me.id}. Msg: {cbq}')
94
- await cbq.message.answer(f"Your referrer is {u.ref_id and u.ref.username}"
95
- f"\nThis is your invite link: {link}"
96
- f"\nGive it to your protege, and approve his request")
97
- await cbq.answer('Wait for your protege request..')
115
+ logging.info(f"Start: {me.id}. Msg: {cbq}")
116
+ await cbq.message.answer(
117
+ f"Your referrer is {u.ref_id and u.ref.username}"
118
+ f"\nThis is your invite link: {link}"
119
+ f"\nGive it to your protege, and approve his request"
120
+ )
121
+ await cbq.answer("Wait for your protege request..")
98
122
 
99
123
 
100
124
  async def user_upsert(u: TgUser | WebAppUser, status: UserStatus = None) -> (User, bool):
101
- pic = (gpp := await u.get_profile_photos(0, 1)).photos and gpp.photos[0][-1].file_unique_id if type(u) is TgUser else (u.photo_url[0] if u.photo_url else None)
102
- udf = {'username': u.username, 'first_name': u.first_name, 'last_name': u.last_name, 'status': UserStatus.MEMBER, 'lang': u.language_code and Lang[u.language_code], 'pic': pic}
125
+ pic = (
126
+ (gpp := await u.get_profile_photos(0, 1)).photos and gpp.photos[0][-1].file_unique_id
127
+ if type(u) is TgUser
128
+ else (u.photo_url[0] if u.photo_url else None)
129
+ )
130
+ udf = {
131
+ "username": u.username,
132
+ "first_name": u.first_name,
133
+ "last_name": u.last_name,
134
+ "status": UserStatus.MEMBER,
135
+ "lang": u.language_code and Lang[u.language_code],
136
+ "pic": pic,
137
+ }
103
138
  if status:
104
- udf.update({'status': status})
139
+ udf.update({"status": status})
105
140
  return await User.update_or_create(udf, id=u.id)
106
141
 
107
142
 
108
143
  @main.my_chat_member()
109
144
  async def user_set_status(my_chat_member: ChatMemberUpdated):
110
145
  u: TgUser = my_chat_member.from_user
111
- new_status = my_chat_member.new_chat_member.status
146
+ new_status = UserStatus[my_chat_member.new_chat_member.status.upper()]
112
147
  await user_upsert(u, status=new_status)
113
148
 
114
149
 
115
- @main.message()
150
+ @main.chat_member(ChatMemberUpdatedFilter(IS_MEMBER >> IS_NOT_MEMBER))
151
+ async def on_user_leave(member: ChatMemberUpdated):
152
+ forum = await Forum[member.chat.id]
153
+ if not forum.joined:
154
+ resp = (
155
+ f"{member.from_user.username or member.from_user.full_name}#{member.from_user.id} "
156
+ f"already leaved from {member.chat.title}#{member.chat.id}"
157
+ )
158
+ logging.error(resp)
159
+ else:
160
+ forum.joined = False
161
+ await forum.save()
162
+ resp = "Bye!"
163
+ return await member.bot.send_message(member.new_chat_member.user.id, resp)
164
+
165
+
166
+ @main.chat_join_request()
167
+ async def on_join_request(req: ChatJoinRequest):
168
+ forum = await Forum[req.chat.id]
169
+ if forum.user_id != req.from_user.id:
170
+ resp = f"{req.chat.title} is chat for user#{forum.user_id}"
171
+ logging.error(resp)
172
+ forum.joined = not await req.decline()
173
+ else:
174
+ resp = "Welcome!"
175
+ forum.joined = await req.approve()
176
+ cp = (await req.bot.get_chat(req.chat.id)).photo
177
+ if not cp:
178
+ pth = path.join(path.dirname(path.abspath(__file__)), "xicon.png")
179
+ await req.chat.set_photo(FSInputFile(pth))
180
+ await forum.save()
181
+ return await req.bot.send_message(req.user_chat_id, resp)
182
+
183
+
184
+ @main.chat_member(ChatMemberUpdatedFilter(IS_NOT_MEMBER >> IS_MEMBER))
185
+ async def on_user_join(member: ChatMemberUpdated):
186
+ forum = await Forum[member.chat.id]
187
+ rm = None
188
+ if forum.user_id != member.from_user.id:
189
+ if member.from_user.id in (6806432376, forum.created_by):
190
+ return
191
+ resp = f"{member.chat.title} is chat for user#{forum.user_id}"
192
+ logging.error(resp)
193
+ await member.bot.ban_chat_member(member.chat.id, member.from_user.id)
194
+ else:
195
+ resp = "Welcome to XyncNetwork"
196
+ rm = InlineKeyboardMarkup(
197
+ inline_keyboard=[[InlineKeyboardButton(text="Go!", web_app=WebAppInfo(url="https://t.me/XyncNetBot/test"))]]
198
+ )
199
+ return await member.bot.send_message(member.new_chat_member.user.id, resp, reply_markup=rm)
200
+
201
+
202
+ @main.message(F.is_topic_message)
203
+ async def order_msg(msg: Message):
204
+ sender = await User[msg.from_user.id]
205
+ cid = msg.chat.shifted_id
206
+ assert sender.forum == cid, "sender is not client"
207
+ if order := await Order.get_or_none(taker__user_id=sender.id, taker_topic=msg.message_thread_id):
208
+ is_taker = True
209
+ elif order := await Order.get_or_none(ad__agent__user_id=sender.id, maker_topic=msg.message_thread_id):
210
+ is_taker = False
211
+ else:
212
+ return await msg.answer("No such order")
213
+ # raise Exception("No such order")
214
+ receiver: User = await (order.ad.agent.user if is_taker else order.taker.user)
215
+ rcv_topic = order.taker_topic if is_taker else order.maker_topic
216
+ await Msg.create(tgid=msg.message_id, txt=msg.text, order_id=order.id, receiver=receiver)
217
+ return await msg.send_copy(receiver.forum, message_thread_id=rcv_topic)
218
+
219
+
220
+ @main.message(
221
+ F.content_type.not_in(
222
+ {
223
+ # ContentType.NEW_CHAT_MEMBERS,
224
+ ContentType.FORUM_TOPIC_CLOSED,
225
+ ContentType.GENERAL_FORUM_TOPIC_HIDDEN,
226
+ # ContentType.LEFT_CHAT_MEMBER,
227
+ ContentType.SUPERGROUP_CHAT_CREATED,
228
+ ContentType.NEW_CHAT_PHOTO,
229
+ # ContentType.FORUM_TOPIC_CREATED,
230
+ # ContentType.FORUM_TOPIC_EDITED,
231
+ # ContentType.FORUM_TOPIC_CLOSED,
232
+ }
233
+ )
234
+ )
116
235
  async def del_cbq(msg: Message):
117
236
  await msg.delete()
@@ -0,0 +1,12 @@
1
+ from aiogram import Router, F
2
+ from aiogram.types import Message
3
+ from xync_schema.models import User
4
+
5
+ r = Router()
6
+
7
+
8
+ # @main.message(F.chat.is_forum)
9
+ @r.message(F.is_topic_message)
10
+ async def order_msg(msg: Message):
11
+ await User[msg.from_user.id]
12
+ msg.message_thread_id
Binary file
@@ -1,16 +1,17 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: xync-bot
3
- Version: 0.2.10
3
+ Version: 0.3.2
4
4
  Summary: Telegram bot with web app for xync net
5
5
  Author-email: Artemiev <mixartemev@gmail.com>
6
- License: MIT
6
+ License: EULA
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
9
  Keywords: aiogram,xync-net
10
- Requires-Python: >=3.11
10
+ Requires-Python: >=3.12
11
11
  Description-Content-Type: text/markdown
12
- Requires-Dist: aiogram
13
- Requires-Dist: python-dotenv
14
- Requires-Dist: xn-api
15
12
  Requires-Dist: xync-schema
16
-
13
+ Provides-Extra: dev
14
+ Requires-Dist: pytest; extra == "dev"
15
+ Requires-Dist: python-dotenv; extra == "dev"
16
+ Requires-Dist: build; extra == "dev"
17
+ Requires-Dist: twine; extra == "dev"
@@ -0,0 +1,11 @@
1
+ xync_bot/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ xync_bot/shared.py,sha256=MlKkTrsT29l7fF6-qAN9FO14cSuXuOuYxbNY5F4S2w4,137
3
+ xync_bot/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ xync_bot/handlers/main.py,sha256=WOaPXjsZ40xUPZi6EHeew-ttee_qxLACt1uVjPC0Ll0,9565
5
+ xync_bot/handlers/order.py,sha256=ZKWDLyiWrXzcR-aHKLBTBCACwp-P0Vvnr22T-EuLHaM,274
6
+ xync_bot/handlers/vpn.py,sha256=qKK55UrjEZeDvu7ljWXNUFBFgXTPTIEaCT2OAmKWky4,2219
7
+ xync_bot/handlers/xicon.png,sha256=O57_kvzhVcCXSoGYZ61m0dW9pizY6gxR8Yj5aeCP0RQ,429283
8
+ xync_bot-0.3.2.dist-info/METADATA,sha256=FwJVU_5hg8oePhgsNeCMiS3b3VThxcpOwLDGZIAh-EE,575
9
+ xync_bot-0.3.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
10
+ xync_bot-0.3.2.dist-info/top_level.txt,sha256=O2IjMc1ryAf0rwIXWohSNT5Kzcs9johgKRDz8lCC0rs,9
11
+ xync_bot-0.3.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.2.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,9 +0,0 @@
1
- xync_bot/__init__.py,sha256=A4PNsNVDgj5Cg4nIAhyhWbWLODalM3xQyrAzM6Cl2n0,1238
2
- xync_bot/shared.py,sha256=MlKkTrsT29l7fF6-qAN9FO14cSuXuOuYxbNY5F4S2w4,137
3
- xync_bot/handlers/__init__.py,sha256=lGPndTeEl1oLFMzFMtKNG2XLL8IecUFj1YIGzkZ55M8,78
4
- xync_bot/handlers/main.py,sha256=AfWoTjBk_kzZCkR_7XfWYzWT2KV9ni_7TguRiJzxGcg,5757
5
- xync_bot/handlers/vpn.py,sha256=qKK55UrjEZeDvu7ljWXNUFBFgXTPTIEaCT2OAmKWky4,2219
6
- xync_bot-0.2.10.dist-info/METADATA,sha256=1CsOEupFK5oWlKfBtCFbqDmqUGT9yYAj4gPnTCClVAI,473
7
- xync_bot-0.2.10.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
8
- xync_bot-0.2.10.dist-info/top_level.txt,sha256=O2IjMc1ryAf0rwIXWohSNT5Kzcs9johgKRDz8lCC0rs,9
9
- xync_bot-0.2.10.dist-info/RECORD,,