-
Notifications
You must be signed in to change notification settings - Fork 62
Expand file tree
/
Copy pathbot.py
More file actions
173 lines (153 loc) · 5.96 KB
/
bot.py
File metadata and controls
173 lines (153 loc) · 5.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
import logging
import sys
import traceback
from contextlib import asynccontextmanager
from pathlib import Path
from aiogram.fsm.storage.redis import RedisStorage
from aiogram.types import BufferedInputFile, URLInputFile
from redis.asyncio import Redis
from sqladmin import Admin
import config
from aiogram import Dispatcher
from fastapi import FastAPI, Request, status, HTTPException
from admin import authentication_backend
from db import create_db_and_tables, engine
import uvicorn
from fastapi.responses import JSONResponse
from enums.cryptocurrency import Cryptocurrency
from models.buy import BuyAdmin
from models.buyItem import BuyItemAdmin
from models.cart import CartAdmin
from models.cartItem import CartItemAdmin
from models.category import CategoryAdmin
from models.coupon import CouponAdmin
from models.deposit import DepositAdmin
from models.item import ItemAdmin
from models.payment import PaymentAdmin
from models.referral import ReferralBonusAdmin
from models.review import ReviewAdmin
from models.shipping_option import ShippingOptionAdmin
from models.subcategory import SubcategoryAdmin
from models.user import UserAdmin
from processing.processing import processing_router
from repositories.button_media import ButtonMediaRepository
from services.media import MediaService
from services.notification import NotificationService
from services.wallet import WalletService
from utils.telegram import create_bot, create_telegram_session
from utils.utils import validate_i18n
redis = Redis(host=config.REDIS_HOST, password=config.REDIS_PASSWORD)
session = create_telegram_session()
bot = create_bot(config.TOKEN, session)
dp = Dispatcher(storage=RedisStorage(redis))
async def _startup() -> None:
await create_db_and_tables()
await bot.set_webhook(
url=config.WEBHOOK_URL,
secret_token=config.WEBHOOK_SECRET_TOKEN
)
static = Path("static")
if static.exists() is False:
static.mkdir()
me = await bot.get_me()
photos = await bot.get_user_profile_photos(me.id)
if photos.total_count == 0:
photo_id_list = []
for admin_id in config.ADMIN_ID_LIST:
try:
msg = await bot.send_photo(chat_id=admin_id,
photo=URLInputFile(url="https://img.freepik.com/premium-vector/no-photo-available-vector-icon-default-image-symbol-picture-coming-soon-web-site-mobile-app_87543-18055.jpg",
filename="no_image.png"))
bot_photo_id = msg.photo[-1].file_id
photo_id_list.append(bot_photo_id)
except Exception as _:
pass
bot_photo_id = photo_id_list[0]
else:
bot_photo_id = photos.photos[0][-1].file_id
with open("static/no_image.jpeg", "w") as f:
f.write(bot_photo_id)
await MediaService.update_inaccessible_media(bot)
validate_i18n()
await ButtonMediaRepository.init_buttons_media()
if config.CRYPTO_FORWARDING_MODE:
for cryptocurrency in Cryptocurrency:
forwarding_address = cryptocurrency.get_forwarding_address()
is_addr_valid = WalletService.validate_withdrawal_address(forwarding_address, cryptocurrency)
if is_addr_valid is False:
logging.error(
"Your withdrawal address for %s cryptocurrency is not configured correctly: %s",
cryptocurrency.name,
forwarding_address
)
sys.exit(1)
for admin in config.ADMIN_ID_LIST:
try:
await bot.send_message(admin, 'Bot is working')
except Exception as e:
logging.warning(e)
async def _shutdown() -> None:
logging.warning('Shutting down..')
await bot.delete_webhook()
await dp.storage.close()
await bot.session.close()
logging.warning('Bye!')
@asynccontextmanager
async def lifespan(app: FastAPI):
await _startup()
try:
yield
finally:
await _shutdown()
app = FastAPI(lifespan=lifespan)
admin = Admin(app=app, engine=engine, authentication_backend=authentication_backend)
admin.add_model_view(UserAdmin)
admin.add_model_view(BuyAdmin)
admin.add_model_view(ShippingOptionAdmin)
admin.add_model_view(CouponAdmin)
admin.add_model_view(CategoryAdmin)
admin.add_model_view(SubcategoryAdmin)
admin.add_model_view(ItemAdmin)
admin.add_model_view(DepositAdmin)
admin.add_model_view(BuyItemAdmin)
admin.add_model_view(PaymentAdmin)
admin.add_model_view(CartAdmin)
admin.add_model_view(CartItemAdmin)
admin.add_model_view(ReferralBonusAdmin)
admin.add_model_view(ReviewAdmin)
app.include_router(processing_router)
@app.post(config.WEBHOOK_PATH)
async def webhook(request: Request):
secret_token = request.headers.get("X-Telegram-Bot-Api-Secret-Token")
if secret_token != config.WEBHOOK_SECRET_TOKEN:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Unauthorized")
try:
update_data = await request.json()
await dp.feed_webhook_update(bot, update_data)
return {"status": "ok"}
except Exception as e:
logging.error(f"Error processing webhook: {e}")
return {"status": "error"}, status.HTTP_500_INTERNAL_SERVER_ERROR
@app.exception_handler(Exception)
async def exception_handler(request: Request, exc: Exception):
traceback_str = traceback.format_exc()
admin_notification = (
f"Critical error caused by {exc}\n\n"
f"Stack trace:\n{traceback_str}"
)
if len(admin_notification) > 4096:
byte_array = bytearray(admin_notification, 'utf-8')
admin_notification = BufferedInputFile(byte_array, "exception.txt")
await NotificationService.send_to_admins(admin_notification, None)
return JSONResponse(
status_code=500,
content={"message": f"An error occurred: {str(exc)}"},
)
def main() -> None:
uvicorn.run(
app,
host=config.WEBAPP_HOST,
port=config.WEBAPP_PORT,
proxy_headers=True,
forwarded_allow_ips="*",
)