xync-bot 0.3.2__tar.gz → 0.3.4__tar.gz

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.

@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: xync-bot
3
- Version: 0.3.2
3
+ Version: 0.3.4
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,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)
@@ -3,7 +3,8 @@ from os import path
3
3
 
4
4
  from aiogram import Router, F
5
5
  from aiogram.enums import ContentType
6
- from aiogram.filters import CommandStart, CommandObject, IS_MEMBER, IS_NOT_MEMBER, ChatMemberUpdatedFilter
6
+ from aiogram.exceptions import TelegramBadRequest
7
+ from aiogram.filters import CommandStart, CommandObject, ChatMemberUpdatedFilter, JOIN_TRANSITION, LEAVE_TRANSITION
7
8
  from aiogram.filters.callback_data import CallbackData
8
9
  from aiogram.types import (
9
10
  User as TgUser,
@@ -17,9 +18,8 @@ from aiogram.types import (
17
18
  FSInputFile,
18
19
  )
19
20
  from aiogram.utils.deep_linking import create_start_link
20
- from aiogram.utils.web_app import WebAppUser
21
- from tg_auth import Lang
22
- from xync_schema.models import User, UserStatus, Order, Msg, Forum
21
+ from xync_bot.handlers import user_upsert
22
+ from xync_schema.models import User, Order, Msg, Forum
23
23
 
24
24
  from xync_bot.shared import NavCallbackData
25
25
 
@@ -45,14 +45,15 @@ home_btns = InlineKeyboardMarkup(
45
45
  async def start_handler(msg: Message, command: CommandObject):
46
46
  me: TgUser = msg.from_user
47
47
  ref_id: int = command.args.isnumeric() and int(command.args)
48
- 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)
49
49
  rm = None
50
+ logging.info(msg, {"src": "start"})
50
51
  if user:
51
52
  rs, rm = f"{me.full_name}, you have registered already😉", home_btns
52
53
  elif not (ref := await User.get_or_none(id=ref_id)):
53
54
  rs = f"No registered user #{ref_id}😬"
54
55
  else: # new user created
55
- user, cr = await user_upsert(me)
56
+ user, cr = await user_upsert(me, False)
56
57
  await user.update_from_dict({"ref": ref}).save()
57
58
  approve_btns = InlineKeyboardMarkup(
58
59
  inline_keyboard=[
@@ -88,7 +89,7 @@ async def phrases_input_request(cb: CallbackQuery, callback_data: RrCallbackData
88
89
 
89
90
  @main.message(CommandStart(deep_link=True)) # attempt to reg by fake link
90
91
  async def fraud_handler(msg: Message):
91
- logging.info(f"Start: {msg.from_user.id}. Msg: {msg}")
92
+ logging.warning(f"Start: {msg.from_user.id}. Msg: {msg}")
92
93
  # todo: alert to admins! Fraud attempt!
93
94
  await msg.answer("🤔")
94
95
 
@@ -96,7 +97,7 @@ async def fraud_handler(msg: Message):
96
97
  @main.message(CommandStart())
97
98
  async def start_no_ref_handler(msg: Message):
98
99
  me = msg.from_user
99
- user, cr = await user_upsert(me)
100
+ user, cr = await user_upsert(me, False)
100
101
  rr = "сначала вы должны найти поручителя, и перейти по его реферальной ссылке.\nhttps://telegra.ph/XyncNet-02-13"
101
102
  if cr: # has ref and created now
102
103
  await msg.answer(f"Здравствуйте {me.full_name}, что бы использовать возможности нашей сети, {rr}")
@@ -109,7 +110,7 @@ async def start_no_ref_handler(msg: Message):
109
110
  @main.callback_query(NavCallbackData.filter(F.to == "ref_link"))
110
111
  async def ref_link_handler(cbq: CallbackQuery):
111
112
  me = cbq.from_user
112
- 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")):
113
114
  return await cbq.answer(f"{me.full_name}, сначала сами получите одобрение поручителя😉")
114
115
  link = await create_start_link(cbq.bot, str(u.id), encode=True)
115
116
  logging.info(f"Start: {me.id}. Msg: {cbq}")
@@ -121,80 +122,72 @@ async def ref_link_handler(cbq: CallbackQuery):
121
122
  await cbq.answer("Wait for your protege request..")
122
123
 
123
124
 
124
- async def user_upsert(u: TgUser | WebAppUser, status: UserStatus = None) -> (User, bool):
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
- }
138
- if status:
139
- udf.update({"status": status})
140
- 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)
141
131
 
142
132
 
143
133
  @main.my_chat_member()
144
134
  async def user_set_status(my_chat_member: ChatMemberUpdated):
135
+ logging.info({"my_chat_member": my_chat_member.model_dump(exclude_none=True)})
145
136
  u: TgUser = my_chat_member.from_user
146
- new_status = UserStatus[my_chat_member.new_chat_member.status.upper()]
147
- 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)
148
139
 
149
140
 
150
- @main.chat_member(ChatMemberUpdatedFilter(IS_MEMBER >> IS_NOT_MEMBER))
141
+ @main.chat_member(ChatMemberUpdatedFilter(LEAVE_TRANSITION))
151
142
  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!"
143
+ logging.info({"user_leave": member.model_dump(exclude_none=True)})
144
+ if 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!"
163
155
  return await member.bot.send_message(member.new_chat_member.user.id, resp)
164
156
 
165
157
 
166
158
  @main.chat_join_request()
167
159
  async def on_join_request(req: ChatJoinRequest):
160
+ logging.info({"join_request": req.model_dump(exclude_none=True)})
168
161
  forum = await Forum[req.chat.id]
169
162
  if forum.user_id != req.from_user.id:
170
163
  resp = f"{req.chat.title} is chat for user#{forum.user_id}"
171
164
  logging.error(resp)
172
165
  forum.joined = not await req.decline()
173
166
  else:
174
- resp = "Welcome!"
167
+ resp = "Your request approved"
175
168
  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
169
  await forum.save()
181
170
  return await req.bot.send_message(req.user_chat_id, resp)
182
171
 
183
172
 
184
- @main.chat_member(ChatMemberUpdatedFilter(IS_NOT_MEMBER >> IS_MEMBER))
173
+ @main.chat_member(ChatMemberUpdatedFilter(JOIN_TRANSITION))
185
174
  async def on_user_join(member: ChatMemberUpdated):
175
+ logging.info({"user_join": member.model_dump(exclude_none=True)})
186
176
  forum = await Forum[member.chat.id]
187
177
  rm = None
188
- if forum.user_id != member.from_user.id:
189
- if member.from_user.id in (6806432376, forum.created_by):
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
190
180
  return
191
181
  resp = f"{member.chat.title} is chat for user#{forum.user_id}"
192
182
  logging.error(resp)
193
- await member.bot.ban_chat_member(member.chat.id, member.from_user.id)
183
+ await member.bot.ban_chat_member(member.chat.id, member.new_chat_member.user.id)
194
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))
195
188
  resp = "Welcome to XyncNetwork"
196
189
  rm = InlineKeyboardMarkup(
197
- inline_keyboard=[[InlineKeyboardButton(text="Go!", web_app=WebAppInfo(url="https://t.me/XyncNetBot/test"))]]
190
+ inline_keyboard=[[InlineKeyboardButton(text="Go!", web_app=WebAppInfo(url="https://test.xync.net/"))]]
198
191
  )
199
192
  return await member.bot.send_message(member.new_chat_member.user.id, resp, reply_markup=rm)
200
193
 
@@ -211,26 +204,41 @@ async def order_msg(msg: Message):
211
204
  else:
212
205
  return await msg.answer("No such order")
213
206
  # raise Exception("No such order")
214
- receiver: User = await (order.ad.agent.user if is_taker else order.taker.user)
207
+ receiver: User = await (order.ad.maker.user if is_taker else order.taker.user)
215
208
  rcv_topic = order.taker_topic if is_taker else order.maker_topic
216
209
  await Msg.create(tgid=msg.message_id, txt=msg.text, order_id=order.id, receiver=receiver)
210
+ logging.info(msg, {"src": "order_msg"})
217
211
  return await msg.send_copy(receiver.forum, message_thread_id=rcv_topic)
218
212
 
219
213
 
220
214
  @main.message(
221
215
  F.content_type.not_in(
222
216
  {
223
- # ContentType.NEW_CHAT_MEMBERS,
224
- ContentType.FORUM_TOPIC_CLOSED,
225
- ContentType.GENERAL_FORUM_TOPIC_HIDDEN,
217
+ ContentType.NEW_CHAT_MEMBERS,
226
218
  # ContentType.LEFT_CHAT_MEMBER,
227
- ContentType.SUPERGROUP_CHAT_CREATED,
228
- ContentType.NEW_CHAT_PHOTO,
219
+ # ContentType.SUPERGROUP_CHAT_CREATED,
220
+ # ContentType.NEW_CHAT_PHOTO,
229
221
  # ContentType.FORUM_TOPIC_CREATED,
230
222
  # ContentType.FORUM_TOPIC_EDITED,
231
- # ContentType.FORUM_TOPIC_CLOSED,
223
+ ContentType.FORUM_TOPIC_CLOSED,
224
+ # ContentType.GENERAL_FORUM_TOPIC_HIDDEN, # deletable
232
225
  }
233
226
  )
234
227
  )
235
228
  async def del_cbq(msg: Message):
236
- 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,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")
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: xync-bot
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: Telegram bot with web app for xync net
5
5
  Author-email: Artemiev <mixartemev@gmail.com>
6
6
  License: EULA
@@ -6,6 +6,7 @@ pyproject.toml
6
6
  test_main.http
7
7
  xync_bot/__init__.py
8
8
  xync_bot/shared.py
9
+ xync_bot/types.py
9
10
  xync_bot.egg-info/PKG-INFO
10
11
  xync_bot.egg-info/SOURCES.txt
11
12
  xync_bot.egg-info/dependency_links.txt
@@ -14,5 +15,6 @@ xync_bot.egg-info/top_level.txt
14
15
  xync_bot/handlers/__init__.py
15
16
  xync_bot/handlers/main.py
16
17
  xync_bot/handlers/order.py
18
+ xync_bot/handlers/photo.py
17
19
  xync_bot/handlers/vpn.py
18
20
  xync_bot/handlers/xicon.png
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes