telegram_libs 0.1.1__tar.gz → 0.1.8__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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 AndreyGritsa
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: telegram_libs
3
- Version: 0.1.1
3
+ Version: 0.1.8
4
4
  Summary: Common libraries for Telegram bots
5
5
  Author: Andrey Gritsaenko gricaenko.95a@gmail.com
6
6
  Requires-Python: >=3.11,<4.0
@@ -8,7 +8,11 @@ Classifier: Programming Language :: Python :: 3
8
8
  Classifier: Programming Language :: Python :: 3.11
9
9
  Classifier: Programming Language :: Python :: 3.12
10
10
  Classifier: Programming Language :: Python :: 3.13
11
+ Requires-Dist: pymongo (>=4.13.0,<5.0.0)
11
12
  Requires-Dist: pytest (>=8.3.5,<9.0.0)
13
+ Requires-Dist: pytest-asyncio (>=1.0.0,<2.0.0)
14
+ Requires-Dist: python-telegram-bot (>=22.1,<23.0)
15
+ Project-URL: Repository, https://github.com/AndreyGritsa/telegram_libs
12
16
  Description-Content-Type: text/markdown
13
17
 
14
18
  # Telegram Libs
@@ -1,14 +1,18 @@
1
1
  [tool.poetry]
2
2
  name = "telegram_libs"
3
- version = "0.1.1"
3
+ version = "0.1.8"
4
4
  description = "Common libraries for Telegram bots"
5
5
  authors = ["Andrey Gritsaenko gricaenko.95a@gmail.com"]
6
6
  readme = "README.md"
7
7
  packages = [{include = "telegram_libs", from = "src"}]
8
+ repository = "https://github.com/AndreyGritsa/telegram_libs"
8
9
 
9
10
  [tool.poetry.dependencies]
10
11
  python = "^3.11"
11
12
  pytest = "^8.3.5"
13
+ python-telegram-bot = "^22.1"
14
+ pytest-asyncio = "^1.0.0"
15
+ pymongo = "^4.13.0"
12
16
 
13
17
  [build-system]
14
18
  requires = ["poetry-core"]
@@ -2,4 +2,4 @@
2
2
  Telegram Libs - Common libraries for Telegram bots
3
3
  """
4
4
 
5
- __version__ = "0.1.0"
5
+ __version__ = "0.1.8"
@@ -0,0 +1,15 @@
1
+ import os
2
+
3
+ required_constants = []
4
+
5
+ BOTS_AMOUNT = os.getenv("BOTS_AMOUNT")
6
+ MONGO_URI = os.getenv("MONGO_URI")
7
+ SUBSCRIPTION_DB_NAME = os.getenv("SUBSCRIPTION_DB_NAME")
8
+
9
+ required_constants.append(("BOTS_AMOUNT", BOTS_AMOUNT))
10
+ required_constants.append(("MONGO_URI", MONGO_URI))
11
+ required_constants.append(("SUBSCRIPTION_DB_NAME", SUBSCRIPTION_DB_NAME))
12
+
13
+ missing_constants = [name for name, value in required_constants if not value]
14
+ if missing_constants:
15
+ raise ValueError(f"Required constants are not set: {', '.join(missing_constants)}")
@@ -0,0 +1,10 @@
1
+ {
2
+ "subscription": {
3
+ "choose_plan": "Choose a subscription plan:",
4
+ "plans": {
5
+ "1month": "1 Month - 250 Stars",
6
+ "3months": "3 Months - 500 Stars",
7
+ "1year": "1 Year - 1600 Stars"
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "subscription": {
3
+ "choose_plan": "Выберите план подписки:",
4
+ "plans": {
5
+ "1month": "1 месяц - 250 Stars",
6
+ "3months": "3 месяца - 500 Stars",
7
+ "1year": "1 год - 1600 Stars"
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,55 @@
1
+ from datetime import datetime
2
+ from pymongo.mongo_client import MongoClient
3
+ from pymongo.server_api import ServerApi
4
+ from telegram_libs.constants import MONGO_URI, SUBSCRIPTION_DB_NAME
5
+
6
+ # Create a new client and connect to the server
7
+ client = MongoClient(MONGO_URI, server_api=ServerApi("1"))
8
+
9
+ # Define the subscription database and collection
10
+ subscription_db = client[SUBSCRIPTION_DB_NAME]
11
+ subscription_collection = subscription_db["subscriptions"]
12
+
13
+
14
+ def get_subscription(user_id: int) -> dict:
15
+ """Get user's subscription data from the shared subscription database."""
16
+ subscription = subscription_collection.find_one({"user_id": user_id})
17
+ if not subscription:
18
+ return {"user_id": user_id, "is_premium": False}
19
+ return subscription
20
+
21
+
22
+ def update_subscription(user_id: int, updates: dict) -> None:
23
+ """Update user's subscription data in the shared subscription database."""
24
+ subscription_collection.update_one(
25
+ {"user_id": user_id},
26
+ {"$set": updates},
27
+ upsert=True
28
+ )
29
+
30
+
31
+ def add_subscription_payment(user_id: int, payment_data: dict) -> None:
32
+ """Add a subscription payment record."""
33
+ subscription_collection.update_one(
34
+ {"user_id": user_id},
35
+ {
36
+ "$push": {"payments": payment_data},
37
+ "$set": {
38
+ "is_premium": True,
39
+ "premium_expiration": payment_data["expiration_date"],
40
+ "last_payment": payment_data["date"]
41
+ }
42
+ },
43
+ upsert=True
44
+ )
45
+
46
+
47
+ def check_subscription_status(user_id: int) -> bool:
48
+ """Check if user has an active subscription."""
49
+ subscription = get_subscription(user_id)
50
+
51
+ if not subscription.get("is_premium"):
52
+ return False
53
+
54
+ expiration = datetime.fromisoformat(subscription["premium_expiration"])
55
+ return expiration > datetime.now()
@@ -0,0 +1,63 @@
1
+ import json
2
+ import os
3
+ from typing import Any
4
+
5
+
6
+ def _load_translations_from_dir(locales_dir: str) -> dict:
7
+ """Helper to load translations from a given directory"""
8
+ translations = {}
9
+ if not os.path.exists(locales_dir):
10
+ print(f"Warning: No 'locales' directory found in {locales_dir}")
11
+ return translations
12
+ for filename in os.listdir(locales_dir):
13
+ if filename.endswith('.json'):
14
+ lang = filename.split('.')[0]
15
+ with open(os.path.join(locales_dir, filename), 'r', encoding='utf-8') as f:
16
+ translations[lang] = json.load(f)
17
+ return translations
18
+
19
+
20
+ def load_translations() -> dict:
21
+ """Load translations from locales directory
22
+
23
+ Returns:
24
+ dict: Translations dictionary
25
+ """
26
+ # Get the project's root directory (where the script is being run from)
27
+ project_root = os.path.abspath(os.getcwd())
28
+ locales_dir = os.path.join(project_root, 'locales')
29
+ return _load_translations_from_dir(locales_dir)
30
+
31
+
32
+ def load_common_translations() -> dict:
33
+ """Load translations from locales directory in the project
34
+
35
+ Returns:
36
+ dict: Translations dictionary
37
+ """
38
+ locales_dir = os.path.join(os.path.dirname(__file__), 'locales')
39
+ return _load_translations_from_dir(locales_dir)
40
+
41
+
42
+ TRANSLATIONS = load_translations()
43
+ COMMON_TRANSLATIONS = load_common_translations()
44
+
45
+
46
+ def t(key: str, lang: str = 'ru', common: bool = False, **kwargs: Any) -> str:
47
+ """Get translation for a key with optional formatting"""
48
+ try:
49
+ # Support nested keys like "buttons.start"
50
+ keys = key.split('.')
51
+ if common:
52
+ value = COMMON_TRANSLATIONS[lang]
53
+ else:
54
+ value = TRANSLATIONS[lang]
55
+ for k in keys:
56
+ value = value[k]
57
+
58
+ return value.format(**kwargs) if kwargs else value
59
+ except KeyError:
60
+ # Fallback to English if translation missing
61
+ if lang != 'en':
62
+ return t(key, 'en', common=common, **kwargs)
63
+ return key # Return the key itself as last resort
@@ -0,0 +1,49 @@
1
+ from telegram import (
2
+ InlineKeyboardButton,
3
+ InlineKeyboardMarkup,
4
+ )
5
+ from telegram import Update
6
+ from telegram.ext import ContextTypes
7
+ from telegram_libs.constants import BOTS_AMOUNT
8
+ from telegram_libs.translation import t
9
+
10
+
11
+ async def get_subscription_keyboard(update: Update, lang: str) -> InlineKeyboardMarkup:
12
+ """Get subscription keyboard
13
+
14
+ Args:
15
+ update (Update): Update object
16
+ lang (str): Language code
17
+
18
+ Returns:
19
+ InlineKeyboardMarkup: Inline keyboard markup
20
+ """
21
+ await update.message.reply_text(
22
+ f"Buying a subscription you will get unlimited access to other {int(BOTS_AMOUNT) - 1} bots, to see all bots click /more"
23
+ )
24
+ return [
25
+ [
26
+ InlineKeyboardButton(
27
+ t("subscription.plans.1month", lang, common=True), callback_data="sub_1month"
28
+ ),
29
+ InlineKeyboardButton(
30
+ t("subscription.plans.3months", lang, common=True), callback_data="sub_3months"
31
+ ),
32
+ ],
33
+ [
34
+ InlineKeyboardButton(
35
+ t("subscription.plans.1year", lang, common=True), callback_data="sub_1year"
36
+ ),
37
+ ],
38
+ ]
39
+
40
+
41
+ async def more_bots_list_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
42
+ message = """Here is the list of all bots: \n\n
43
+ - <a href="https://t.me/MagMediaBot">Remove Background</a>
44
+ - <a href="https://t.me/UpscaleImageGBot">Upscale Image</a>
45
+ - <a href="https://t.me/GenerateBackgroundGBot">Generate a Background</a>
46
+ - <a href="https://t.me/kudapoyti_go_bot">Recommend a place to visit</a>
47
+ - <a href="https://t.me/TryOnOutfitGBot">Try On Outfit</a>
48
+ """
49
+ await update.message.reply_text(message, disable_web_page_preview=True, parse_mode='HTML')
@@ -1,34 +0,0 @@
1
- import json
2
- import os
3
-
4
- def load_translations():
5
- translations = {}
6
- # Assume 'locales' is at the project root
7
- project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
8
- locales_dir = os.path.join(project_root, 'locales')
9
-
10
- for filename in os.listdir(locales_dir):
11
- if filename.endswith('.json'):
12
- lang = filename.split('.')[0]
13
- with open(os.path.join(locales_dir, filename), 'r', encoding='utf-8') as f:
14
- translations[lang] = json.load(f)
15
-
16
- return translations
17
-
18
- TRANSLATIONS = load_translations()
19
-
20
- def t(key, lang='ru', **kwargs):
21
- """Get translation for a key with optional formatting"""
22
- try:
23
- # Support nested keys like "buttons.start"
24
- keys = key.split('.')
25
- value = TRANSLATIONS[lang]
26
- for k in keys:
27
- value = value[k]
28
-
29
- return value.format(**kwargs) if kwargs else value
30
- except KeyError:
31
- # Fallback to English if translation missing
32
- if lang != 'en':
33
- return t(key, 'en', **kwargs)
34
- return key # Return the key itself as last resort
File without changes