xync-bot 0.3.1__py3-none-any.whl → 0.3.3__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.

@@ -0,0 +1,8 @@
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)
xync_bot/handlers/main.py CHANGED
@@ -1,6 +1,10 @@
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.exceptions import TelegramBadRequest
7
+ from aiogram.filters import CommandStart, CommandObject, ChatMemberUpdatedFilter, JOIN_TRANSITION, LEAVE_TRANSITION
4
8
  from aiogram.filters.callback_data import CallbackData
5
9
  from aiogram.types import (
6
10
  User as TgUser,
@@ -9,11 +13,13 @@ from aiogram.types import (
9
13
  InlineKeyboardMarkup,
10
14
  InlineKeyboardButton,
11
15
  CallbackQuery,
16
+ ChatJoinRequest,
17
+ WebAppInfo,
18
+ FSInputFile,
12
19
  )
13
20
  from aiogram.utils.deep_linking import create_start_link
14
- from aiogram.utils.web_app import WebAppUser
15
- from tg_auth import Lang
16
- from xync_schema.models import User, UserStatus
21
+ from xync_bot.handlers import user_upsert
22
+ from xync_schema.models import User, Order, Msg, Forum
17
23
 
18
24
  from xync_bot.shared import NavCallbackData
19
25
 
@@ -39,14 +45,15 @@ home_btns = InlineKeyboardMarkup(
39
45
  async def start_handler(msg: Message, command: CommandObject):
40
46
  me: TgUser = msg.from_user
41
47
  ref_id: int = command.args.isnumeric() and int(command.args)
42
- user = await User.get_or_none(id=me.id, status__gte=UserStatus.RESTRICTED)
48
+ user = await User.get_or_none(id=me.id, blocked=False)
43
49
  rm = None
50
+ logging.info(msg, {"src": "start"})
44
51
  if user:
45
52
  rs, rm = f"{me.full_name}, you have registered already😉", home_btns
46
53
  elif not (ref := await User.get_or_none(id=ref_id)):
47
54
  rs = f"No registered user #{ref_id}😬"
48
55
  else: # new user created
49
- user, cr = await user_upsert(me)
56
+ user, cr = await user_upsert(me, False)
50
57
  await user.update_from_dict({"ref": ref}).save()
51
58
  approve_btns = InlineKeyboardMarkup(
52
59
  inline_keyboard=[
@@ -82,7 +89,7 @@ async def phrases_input_request(cb: CallbackQuery, callback_data: RrCallbackData
82
89
 
83
90
  @main.message(CommandStart(deep_link=True)) # attempt to reg by fake link
84
91
  async def fraud_handler(msg: Message):
85
- logging.info(f"Start: {msg.from_user.id}. Msg: {msg}")
92
+ logging.warning(f"Start: {msg.from_user.id}. Msg: {msg}")
86
93
  # todo: alert to admins! Fraud attempt!
87
94
  await msg.answer("🤔")
88
95
 
@@ -90,7 +97,7 @@ async def fraud_handler(msg: Message):
90
97
  @main.message(CommandStart())
91
98
  async def start_no_ref_handler(msg: Message):
92
99
  me = msg.from_user
93
- user, cr = await user_upsert(me)
100
+ user, cr = await user_upsert(me, False)
94
101
  rr = "сначала вы должны найти поручителя, и перейти по его реферальной ссылке.\nhttps://telegra.ph/XyncNet-02-13"
95
102
  if cr: # has ref and created now
96
103
  await msg.answer(f"Здравствуйте {me.full_name}, что бы использовать возможности нашей сети, {rr}")
@@ -103,7 +110,7 @@ async def start_no_ref_handler(msg: Message):
103
110
  @main.callback_query(NavCallbackData.filter(F.to == "ref_link"))
104
111
  async def ref_link_handler(cbq: CallbackQuery):
105
112
  me = cbq.from_user
106
- if not (u := await User.get_or_none(id=me.id, status__gt=UserStatus.RESTRICTED).prefetch_related("ref")):
113
+ if not (u := await User.get_or_none(id=me.id, blocked=False).prefetch_related("ref")):
107
114
  return await cbq.answer(f"{me.full_name}, сначала сами получите одобрение поручителя😉")
108
115
  link = await create_start_link(cbq.bot, str(u.id), encode=True)
109
116
  logging.info(f"Start: {me.id}. Msg: {cbq}")
@@ -115,32 +122,123 @@ async def ref_link_handler(cbq: CallbackQuery):
115
122
  await cbq.answer("Wait for your protege request..")
116
123
 
117
124
 
118
- async def user_upsert(u: TgUser | WebAppUser, status: UserStatus = None) -> (User, bool):
119
- pic = (
120
- (gpp := await u.get_profile_photos(0, 1)).photos and gpp.photos[0][-1].file_unique_id
121
- if type(u) is TgUser
122
- else (u.photo_url[0] if u.photo_url else None)
123
- )
124
- udf = {
125
- "username": u.username,
126
- "first_name": u.first_name,
127
- "last_name": u.last_name,
128
- "status": UserStatus.MEMBER,
129
- "lang": u.language_code and Lang[u.language_code],
130
- "pic": pic,
131
- }
132
- if status:
133
- udf.update({"status": status})
134
- return await User.update_or_create(udf, id=u.id)
125
+ @main.my_chat_member(F.chat.type == "private") # my_chat_member is fired on add bot to any chat. filter for preventing
126
+ async def my_user_set_status(my_chat_member: ChatMemberUpdated):
127
+ logging.info({"my_chat_member": my_chat_member.model_dump(exclude_none=True)})
128
+ u: TgUser = my_chat_member.from_user
129
+ blocked = my_chat_member.new_chat_member.status in ("left", "kicked")
130
+ await user_upsert(u, blocked)
135
131
 
136
132
 
137
133
  @main.my_chat_member()
138
134
  async def user_set_status(my_chat_member: ChatMemberUpdated):
135
+ logging.info({"my_chat_member": my_chat_member.model_dump(exclude_none=True)})
139
136
  u: TgUser = my_chat_member.from_user
140
- new_status = my_chat_member.new_chat_member.status
141
- await user_upsert(u, status=new_status)
137
+ blocked = my_chat_member.new_chat_member.status in ("left", "kicked")
138
+ await user_upsert(u, blocked)
139
+
140
+
141
+ @main.chat_member(ChatMemberUpdatedFilter(LEAVE_TRANSITION))
142
+ async def on_user_leave(member: ChatMemberUpdated):
143
+ logging.info({"user_leave": member.model_dump(exclude_none=True)})
144
+ forum = await Forum[member.chat.id]
145
+ if not forum.joined:
146
+ resp = (
147
+ f"{member.from_user.username or member.from_user.full_name}#{member.from_user.id} "
148
+ f"already leaved from {member.chat.title}#{member.chat.id}"
149
+ )
150
+ logging.error(resp)
151
+ else:
152
+ forum.joined = False
153
+ await forum.save()
154
+ resp = "Bye!"
155
+ return await member.bot.send_message(member.new_chat_member.user.id, resp)
156
+
157
+
158
+ @main.chat_join_request()
159
+ async def on_join_request(req: ChatJoinRequest):
160
+ logging.info({"join_request": req.model_dump(exclude_none=True)})
161
+ forum = await Forum[req.chat.id]
162
+ if forum.user_id != req.from_user.id:
163
+ resp = f"{req.chat.title} is chat for user#{forum.user_id}"
164
+ logging.error(resp)
165
+ forum.joined = not await req.decline()
166
+ else:
167
+ resp = "Your request approved"
168
+ forum.joined = await req.approve()
169
+ await forum.save()
170
+ return await req.bot.send_message(req.user_chat_id, resp)
142
171
 
143
172
 
144
- @main.message()
173
+ @main.chat_member(ChatMemberUpdatedFilter(JOIN_TRANSITION))
174
+ async def on_user_join(member: ChatMemberUpdated):
175
+ logging.info({"user_join": member.model_dump(exclude_none=True)})
176
+ forum = await Forum[member.chat.id]
177
+ rm = None
178
+ if forum.user_id != member.new_chat_member.user.id:
179
+ if member.new_chat_member.user.id in (6806432376, forum.created_by_id): # 6806432376=xyncNetBot
180
+ return
181
+ resp = f"{member.chat.title} is chat for user#{forum.user_id}"
182
+ logging.error(resp)
183
+ await member.bot.ban_chat_member(member.chat.id, member.new_chat_member.user.id)
184
+ else:
185
+ if not (await member.bot.get_chat(member.chat.id)).photo:
186
+ pth = path.join(path.dirname(path.abspath(__file__)), "xicon.png")
187
+ await member.chat.set_photo(FSInputFile(pth))
188
+ resp = "Welcome to XyncNetwork"
189
+ rm = InlineKeyboardMarkup(
190
+ inline_keyboard=[[InlineKeyboardButton(text="Go!", web_app=WebAppInfo(url="https://test.xync.net/"))]]
191
+ )
192
+ return await member.bot.send_message(member.new_chat_member.user.id, resp, reply_markup=rm)
193
+
194
+
195
+ @main.message(F.is_topic_message)
196
+ async def order_msg(msg: Message):
197
+ sender = await User[msg.from_user.id]
198
+ cid = msg.chat.shifted_id
199
+ assert sender.forum == cid, "sender is not client"
200
+ if order := await Order.get_or_none(taker__user_id=sender.id, taker_topic=msg.message_thread_id):
201
+ is_taker = True
202
+ elif order := await Order.get_or_none(ad__agent__user_id=sender.id, maker_topic=msg.message_thread_id):
203
+ is_taker = False
204
+ else:
205
+ return await msg.answer("No such order")
206
+ # raise Exception("No such order")
207
+ receiver: User = await (order.ad.maker.user if is_taker else order.taker.user)
208
+ rcv_topic = order.taker_topic if is_taker else order.maker_topic
209
+ await Msg.create(tgid=msg.message_id, txt=msg.text, order_id=order.id, receiver=receiver)
210
+ logging.info(msg, {"src": "order_msg"})
211
+ return await msg.send_copy(receiver.forum, message_thread_id=rcv_topic)
212
+
213
+
214
+ @main.message(
215
+ F.content_type.not_in(
216
+ {
217
+ ContentType.NEW_CHAT_MEMBERS,
218
+ # ContentType.LEFT_CHAT_MEMBER,
219
+ # ContentType.SUPERGROUP_CHAT_CREATED,
220
+ # ContentType.NEW_CHAT_PHOTO,
221
+ # ContentType.FORUM_TOPIC_CREATED,
222
+ # ContentType.FORUM_TOPIC_EDITED,
223
+ ContentType.FORUM_TOPIC_CLOSED,
224
+ # ContentType.GENERAL_FORUM_TOPIC_HIDDEN, # deletable
225
+ }
226
+ )
227
+ )
145
228
  async def del_cbq(msg: Message):
146
- await msg.delete()
229
+ try:
230
+ await msg.delete()
231
+ logging.info({"DELETED": msg.model_dump(exclude_none=True)})
232
+ except TelegramBadRequest:
233
+ logging.error({"NOT_DELETED": msg.model_dump(exclude_none=True)})
234
+
235
+
236
+ @main.message()
237
+ async def all_rest(msg: Message):
238
+ logging.warning(
239
+ {
240
+ "NO_HANDLED": msg.model_dump(
241
+ exclude_none=True,
242
+ )
243
+ }
244
+ )
@@ -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
@@ -0,0 +1,36 @@
1
+ from aiogram import Router, F
2
+ from aiogram.fsm.context import FSMContext
3
+ from aiogram.fsm.state import State
4
+ from aiogram.types import User as TgUser, Message
5
+ from x_auth.enums import Role
6
+ from xync_schema.models import User, Ex
7
+
8
+ photo = Router()
9
+ exns = State("ex_name")
10
+
11
+
12
+ @photo.message(F.photo | F.sticker)
13
+ async def photo_upload(msg: Message, state: FSMContext):
14
+ u: TgUser = msg.from_user
15
+ if not await User.get_or_none(id=u.id, blocked=False, role=Role.ADMIN):
16
+ return await msg.answer("No user")
17
+ if f := msg.sticker:
18
+ await state.set_data({"fid": f.file_id})
19
+ await state.set_state(exns)
20
+ return await msg.answer("Ex name pls")
21
+ res = await set_ex_name(msg.caption, msg.photo[-1].file_id)
22
+ return await msg.answer(res or "No ex", parse_mode="HTML")
23
+
24
+
25
+ async def set_ex_name(name: str, fid: str) -> str | None:
26
+ if ex := await Ex.get_or_none(name=name):
27
+ ex.logo = fid
28
+ await ex.save()
29
+ return fid
30
+ return None
31
+
32
+
33
+ @photo.message(exns)
34
+ async def ex_name(msg: Message, state: FSMContext):
35
+ res = await set_ex_name(msg.text, await state.get_value("fid"))
36
+ return await msg.answer(res or "No ex" + msg.text, parse_mode="HTML")
Binary file
xync_bot/types.py ADDED
File without changes
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: xync-bot
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: Telegram bot with web app for xync net
5
5
  Author-email: Artemiev <mixartemev@gmail.com>
6
6
  License: EULA
@@ -0,0 +1,13 @@
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=lisWrtONG3P2aJdgXQNYMPoeaAuy0rIATqAV7GKtQQ4,10104
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.3.dist-info/METADATA,sha256=GcRnoo6pjNxKMCaOav3OLexTHUI8OFYOPfTOk8sFE7g,575
11
+ xync_bot-0.3.3.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
12
+ xync_bot-0.3.3.dist-info/top_level.txt,sha256=O2IjMc1ryAf0rwIXWohSNT5Kzcs9johgKRDz8lCC0rs,9
13
+ xync_bot-0.3.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (77.0.3)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,9 +0,0 @@
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=aA4UBt2uquG3pd443LEwTu4HDh7fmvRmy0isnZuQJuc,5965
5
- xync_bot/handlers/vpn.py,sha256=qKK55UrjEZeDvu7ljWXNUFBFgXTPTIEaCT2OAmKWky4,2219
6
- xync_bot-0.3.1.dist-info/METADATA,sha256=5lltA3nKr5RtnXAeSlKaFmZ3oOUakjxFcHm1s3nLUoA,575
7
- xync_bot-0.3.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
8
- xync_bot-0.3.1.dist-info/top_level.txt,sha256=O2IjMc1ryAf0rwIXWohSNT5Kzcs9johgKRDz8lCC0rs,9
9
- xync_bot-0.3.1.dist-info/RECORD,,