xync-bot 0.2.10__tar.gz → 0.3.1__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.

@@ -0,0 +1,4 @@
1
+ WH_DOMAIN=https://
2
+ TWA_DOMAIN=https://
3
+ TOKEN=
4
+ DB_URL=postgres://user:pwd@host/db_name
@@ -0,0 +1,8 @@
1
+ /.idea
2
+ /venv
3
+ /.env
4
+ __pycache__
5
+ *.pyc
6
+ *.egg-info
7
+ /build
8
+ /dist
@@ -0,0 +1,36 @@
1
+ repos:
2
+ - repo: local
3
+ hooks:
4
+ - id: tag
5
+ name: tag
6
+ ### make tag with next ver only if "fix" in commit_msg or starts with "feat"
7
+ entry: bash -c 'grep -e ^feat -e fix .git/COMMIT_EDITMSG && make patch || exit 0'
8
+ language: system
9
+ verbose: true
10
+ pass_filenames: false
11
+ always_run: true
12
+ stages: [post-commit]
13
+
14
+ - id: build
15
+ name: build
16
+ ### build & upload package only for "main" branch push
17
+ entry: bash -c 'echo $PRE_COMMIT_LOCAL_BRANCH | grep /main && make build || echo 0'
18
+ language: system
19
+ pass_filenames: false
20
+ verbose: true
21
+ require_serial: true
22
+ stages: [pre-push]
23
+
24
+ - repo: https://github.com/astral-sh/ruff-pre-commit
25
+ ### Ruff version.
26
+ rev: v0.6.4
27
+ hooks:
28
+ ### Run the linter.
29
+ - id: ruff
30
+ args: [--fix, --unsafe-fixes]
31
+ stages: [pre-commit]
32
+ ### Run the formatter.
33
+ - id: ruff-format
34
+ types_or: [python, pyi]
35
+ verbose: true
36
+ stages: [pre-commit]
@@ -1,15 +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.1
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
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,24 @@
1
+ include .env
2
+ PACKAGE := xync_bot
3
+ VPYTHON := $(VENV)/bin/python
4
+
5
+ .PHONY: all install pre-commit clean build twine patch
6
+
7
+ all:
8
+ make install clean build
9
+
10
+ install: $(VENV)
11
+ $(VPYTHON) -m pip install .[dev]; make pre-commit
12
+ pre-commit: .pre-commit-config.yaml
13
+ pre-commit install -t pre-commit -t post-commit -t pre-push
14
+
15
+ clean: dist $(PACKAGE).egg-info
16
+ rm -rf dist/* $(PACKAGE).egg-info $(PACKAGE)/__pycache__ dist/__pycache__
17
+
18
+ build: $(VENV)
19
+ $(VPYTHON) -m build; make twine
20
+ twine: dist
21
+ $(VPYTHON) -m twine upload dist/* --skip-existing
22
+
23
+ patch:
24
+ git tag `$(VPYTHON) -m setuptools_scm --strip-dev`; git push --tags --prune -f
@@ -0,0 +1,42 @@
1
+ [project]
2
+ name = "xync-bot"
3
+ requires-python = ">=3.12"
4
+ authors = [
5
+ {name = "Artemiev", email = "mixartemev@gmail.com"},
6
+ ]
7
+ keywords = ["aiogram", "xync-net"]
8
+ description = "Telegram bot with web app for xync net"
9
+ readme = "README.md"
10
+ license = {text = "EULA"}
11
+ dynamic = ["version"]
12
+ dependencies = [
13
+ "xync-schema",
14
+ ]
15
+ [project.optional-dependencies]
16
+ dev = [
17
+ "pytest",
18
+ "python-dotenv",
19
+ "build",
20
+ "twine",
21
+ ]
22
+
23
+ [project.urls]
24
+ Homepage = "https://gitlab.com/xync/back/tg-bot"
25
+ Repository = "https://gitlab.com/xync/back/tg-bot"
26
+
27
+ [build-system]
28
+ requires = ["setuptools>=64", "setuptools-scm[toml]>=8"]
29
+ build-backend = "setuptools.build_meta"
30
+ [tool.setuptools_scm]
31
+ version_scheme = "python-simplified-semver" # if "feature" in `branch_name` SEMVER_MINOR++ else SEMVER_PATCH++
32
+ local_scheme = "no-local-version"
33
+
34
+ [tool.pytest.ini_options]
35
+ asyncio_mode = "auto"
36
+ asyncio_default_fixture_loop_scope = "function"
37
+
38
+ [tool.ruff]
39
+ line-length = 120
40
+
41
+ [tool.setuptools]
42
+ packages = ["xync_bot", "xync_bot.handlers"]
@@ -0,0 +1,9 @@
1
+ # Test your FastAPI endpoints
2
+
3
+ GET http://127.0.0.1:8000/
4
+ Accept: application/json
5
+ ###
6
+
7
+ GET http://127.0.0.1:8000/hello/User
8
+ Accept: application/json
9
+ ###
File without changes
File without changes
@@ -2,10 +2,18 @@ import logging
2
2
  from aiogram import Router, F
3
3
  from aiogram.filters import CommandStart, CommandObject
4
4
  from aiogram.filters.callback_data import CallbackData
5
- from aiogram.types import User as TgUser, ChatMemberUpdated, Message, InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery
5
+ from aiogram.types import (
6
+ User as TgUser,
7
+ ChatMemberUpdated,
8
+ Message,
9
+ InlineKeyboardMarkup,
10
+ InlineKeyboardButton,
11
+ CallbackQuery,
12
+ )
6
13
  from aiogram.utils.deep_linking import create_start_link
7
14
  from aiogram.utils.web_app import WebAppUser
8
- from xync_schema.models import User, UserStatus, Lang
15
+ from tg_auth import Lang
16
+ from xync_schema.models import User, UserStatus
9
17
 
10
18
  from xync_bot.shared import NavCallbackData
11
19
 
@@ -18,10 +26,13 @@ class RrCallbackData(CallbackData, prefix="reg_res"): # registration response
18
26
 
19
27
 
20
28
  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
- ]])
29
+ inline_keyboard=[
30
+ [
31
+ InlineKeyboardButton(text="Invite", callback_data=NavCallbackData(to="ref_link").pack()),
32
+ InlineKeyboardButton(text="Get VPN", callback_data=NavCallbackData(to="get_vpn").pack()),
33
+ ]
34
+ ]
35
+ )
25
36
 
26
37
 
27
38
  @main.message(CommandStart(deep_link=True, deep_link_encoded=True))
@@ -31,19 +42,24 @@ async def start_handler(msg: Message, command: CommandObject):
31
42
  user = await User.get_or_none(id=me.id, status__gte=UserStatus.RESTRICTED)
32
43
  rm = None
33
44
  if user:
34
- rs, rm = f'{me.full_name}, you have registered already😉', home_btns
45
+ rs, rm = f"{me.full_name}, you have registered already😉", home_btns
35
46
  elif not (ref := await User.get_or_none(id=ref_id)):
36
- rs = f'No registered user #{ref_id}😬'
47
+ rs = f"No registered user #{ref_id}😬"
37
48
  else: # new user created
38
49
  user, cr = await user_upsert(me)
39
- await user.update_from_dict({'ref': ref}).save()
50
+ await user.update_from_dict({"ref": ref}).save()
40
51
  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...')
52
+ inline_keyboard=[
53
+ [
54
+ InlineKeyboardButton(text="Отклонить", callback_data=RrCallbackData(to=user.id, res=False).pack()),
55
+ InlineKeyboardButton(text="Одобрить", callback_data=RrCallbackData(to=user.id, res=True).pack()),
56
+ ]
57
+ ]
58
+ )
59
+ await msg.bot.send_message(
60
+ ref.id, f"{me.full_name} просит что б Вы взяли за него/ее ответственность", reply_markup=approve_btns
61
+ )
62
+ return await msg.answer(f"Please wait for @{ref.username} approving...")
47
63
  return await msg.answer(rs, reply_markup=rm)
48
64
 
49
65
 
@@ -53,55 +69,68 @@ async def phrases_input_request(cb: CallbackQuery, callback_data: RrCallbackData
53
69
  if callback_data.res:
54
70
  # protege.status = UserStatus.RESTRICTED
55
71
  await protege.save()
56
- rs = f'{cb.from_user.full_name}, теперь Вы несете ответветвенность за {protege.username}'
72
+ rs = f"{cb.from_user.full_name}, теперь Вы несете ответветвенность за {protege.username}"
57
73
  else:
58
74
  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)
75
+ res = {True: "одобрил", False: "отклонил"}
76
+ txt = f"{cb.from_user.full_name} {res[callback_data.res]} вашу регистрацию"
77
+ txt, rm = (f"Поздравляем! {txt}💥", home_btns) if callback_data.res else (f"К сожалению {txt}😢", None)
62
78
  await cb.bot.send_message(protege.id, txt, reply_markup=rm)
63
- await cb.answer('👌🏼')
79
+ await cb.answer("👌🏼")
64
80
  await cb.message.edit_text(rs)
65
81
 
66
82
 
67
83
  @main.message(CommandStart(deep_link=True)) # attempt to reg by fake link
68
84
  async def fraud_handler(msg: Message):
69
- logging.info(f'Start: {msg.from_user.id}. Msg: {msg}')
85
+ logging.info(f"Start: {msg.from_user.id}. Msg: {msg}")
70
86
  # todo: alert to admins! Fraud attempt!
71
- await msg.answer('🤔')
87
+ await msg.answer("🤔")
72
88
 
73
89
 
74
90
  @main.message(CommandStart())
75
91
  async def start_no_ref_handler(msg: Message):
76
92
  me = msg.from_user
77
93
  user, cr = await user_upsert(me)
78
- rr = 'сначала вы должны найти поручителя, и перейти по его реферальной ссылке.\nhttps://telegra.ph/XyncNet-02-13'
94
+ rr = "сначала вы должны найти поручителя, и перейти по его реферальной ссылке.\nhttps://telegra.ph/XyncNet-02-13"
79
95
  if cr: # has ref and created now
80
- await msg.answer(f'Здравствуйте {me.full_name}, что бы использовать возможности нашей сети, {rr}')
96
+ await msg.answer(f"Здравствуйте {me.full_name}, что бы использовать возможности нашей сети, {rr}")
81
97
  elif not user.ref_id:
82
98
  await msg.answer(rr.capitalize())
83
99
  else:
84
- await msg.answer(f'{me.full_name}, не балуйтесь, вы и так уже активный участник👌🏼', reply_markup=home_btns)
100
+ await msg.answer(f"{me.full_name}, не балуйтесь, вы и так уже активный участник👌🏼", reply_markup=home_btns)
85
101
 
86
102
 
87
- @main.callback_query(NavCallbackData.filter(F.to == 'ref_link'))
103
+ @main.callback_query(NavCallbackData.filter(F.to == "ref_link"))
88
104
  async def ref_link_handler(cbq: CallbackQuery):
89
105
  me = cbq.from_user
90
- if not (u := await User.get_or_none(id=me.id, status__gt=UserStatus.RESTRICTED).prefetch_related('ref')):
106
+ if not (u := await User.get_or_none(id=me.id, status__gt=UserStatus.RESTRICTED).prefetch_related("ref")):
91
107
  return await cbq.answer(f"{me.full_name}, сначала сами получите одобрение поручителя😉")
92
108
  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..')
109
+ logging.info(f"Start: {me.id}. Msg: {cbq}")
110
+ await cbq.message.answer(
111
+ f"Your referrer is {u.ref_id and u.ref.username}"
112
+ f"\nThis is your invite link: {link}"
113
+ f"\nGive it to your protege, and approve his request"
114
+ )
115
+ await cbq.answer("Wait for your protege request..")
98
116
 
99
117
 
100
118
  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}
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
+ }
103
132
  if status:
104
- udf.update({'status': status})
133
+ udf.update({"status": status})
105
134
  return await User.update_or_create(udf, id=u.id)
106
135
 
107
136
 
@@ -1,15 +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.1
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
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"
@@ -1,4 +1,9 @@
1
+ .env.dist
2
+ .gitignore
3
+ .pre-commit-config.yaml
4
+ makefile
1
5
  pyproject.toml
6
+ test_main.http
2
7
  xync_bot/__init__.py
3
8
  xync_bot/shared.py
4
9
  xync_bot.egg-info/PKG-INFO
@@ -1,4 +1,7 @@
1
- aiogram
2
- python-dotenv
3
- xn-api
4
1
  xync-schema
2
+
3
+ [dev]
4
+ pytest
5
+ python-dotenv
6
+ build
7
+ twine
@@ -1,24 +0,0 @@
1
- [project]
2
- name = "xync-bot"
3
- requires-python = ">=3.11"
4
- authors = [
5
- {name = "Artemiev", email = "mixartemev@gmail.com"},
6
- ]
7
- keywords = ["aiogram", "xync-net"]
8
- description = "Telegram bot with web app for xync net"
9
- readme = "README.md"
10
- license = {text = "MIT"}
11
- dependencies = [
12
- "aiogram",
13
- "python-dotenv",
14
- "xn-api",
15
- "xync-schema",
16
- ]
17
- version = "0.2.10"
18
-
19
- [project.urls]
20
- Homepage = "https://gitlab.com/xync/back/tg-bot"
21
- Repository = "https://gitlab.com/xync/back/tg-bot"
22
-
23
- [tool.setuptools]
24
- packages = ["xync_bot", "xync_bot.handlers"]
@@ -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
File without changes
File without changes