25 Commits

Author SHA1 Message Date
234b73add0 Merge pull request 'Bug fixes and small structural changes' (#7) from dev into master
Reviewed-on: profitroll/HoloCheckerBot#7
2023-01-06 17:01:20 +02:00
742b529c33 Moved templates classes into another module 2023-01-06 15:59:09 +01:00
78a37ca186 Placed exceptions to errors module 2023-01-06 15:49:51 +01:00
374effd5d7 Fixed bugs of /message and now using cached media 2023-01-06 13:21:16 +01:00
Profitroll
1195df894c Added documents support for spoilers 2023-01-05 21:15:34 +01:00
Profitroll
67f1ce535f Small fixes 2023-01-05 20:47:30 +01:00
Profitroll
b6d45545fc User search improved 2023-01-05 20:47:02 +01:00
Profitroll
59dafc004d LabelSettingError added 2023-01-05 20:46:47 +01:00
Profitroll
57518399a1 Sponsorship handler removed 2023-01-05 20:46:04 +01:00
Profitroll
ee288a1983 Photo ID used instead of files for sponsorships 2023-01-05 20:45:35 +01:00
373f2332a0 Updated requirements 2023-01-05 15:51:25 +01:00
f4fb85f7a4 Merge pull request 'Removed legacy, fixed some bugs, improved spoilers' (#6) from dev into master
Reviewed-on: profitroll/HoloCheckerBot#6
2023-01-05 16:49:35 +02:00
02a6960391 Fixed forwarding spoilers to admin group 2023-01-05 15:48:34 +01:00
7939f8b65e Minor spoiler category fixes 2023-01-05 14:52:57 +01:00
5b28f9f588 Caption and category added for spoilers 2023-01-05 14:34:02 +01:00
6e44177907 Shutdown time is now added on KeyboardInterrupt 2023-01-05 14:33:23 +01:00
4f0b9f8e3a Fixed dict key for startup message 2023-01-05 13:16:11 +01:00
78dee0591c /cancel now removes reply markup 2023-01-05 13:12:22 +01:00
b0b0f04a9b Added down time messages 2023-01-05 13:08:08 +01:00
9e009aea43 Minor naming improvements 2023-01-05 13:01:57 +01:00
42d00383bf Removed legacy 2023-01-05 13:01:18 +01:00
4fba305b05 Merge pull request 'Small fix for spoiler with an empty description' (#5) from dev into master
Reviewed-on: profitroll/HoloCheckerBot#5
2023-01-05 13:54:19 +02:00
68c7cc0ada Merge pull request 'Spoilers, major command system improvements' (#4) from dev into master
Reviewed-on: profitroll/HoloCheckerBot#4
2023-01-05 13:45:14 +02:00
79304816b0 Merge pull request '/cancel, /identify, sponsorships improvements and fixes' (#3) from dev into master
Reviewed-on: profitroll/HoloCheckerBot#3
2023-01-03 16:45:20 +02:00
2cfa5a8f8d Merge pull request '/nearby, subscriptions check, geocoding' (#2) from dev into master
Reviewed-on: profitroll/HoloCheckerBot#2
2023-01-02 12:16:38 +02:00
26 changed files with 289 additions and 304 deletions

View File

@@ -0,0 +1,24 @@
"""Exceptions that are meant to be used by HoloUser class
and other modules that handle those exceptions"""
class UserNotFoundError(Exception):
"""HoloUser could not find user with such an ID in database"""
def __init__(self, user, user_id):
self.user = user
self.user_id = user_id
super().__init__(f"User of type {type(self.user)} with id {self.user_id} was not found")
class UserInvalidError(Exception):
"""Provided to HoloUser object is not supported"""
def __init__(self, user):
self.user = user
super().__init__(f"Could not find HoloUser by using {type(self.user)} as an input type")
class LabelTooLongError(Exception):
def __init__(self, label: str) -> None:
self.label = label
super().__init__(f"Could not set label to '{label}' because it is {len(label)} characters long (16 is maximum)")
class LabelSettingError(Exception):
def __init__(self, exp: Exception, trace: str) -> None:
super().__init__(f"❌ **Could not set label**\n\nException: `{exp}`\n\n**Traceback:**\n```\n{trace}\n```")

View File

@@ -1,75 +1,16 @@
from datetime import datetime
from traceback import print_exc
from traceback import format_exc
from app import app, isAnAdmin
from typing import Any, List, Literal, Union
from pyrogram.types import User, ChatMember, ChatPrivileges, Chat, Message, Photo, Video, Document, Animation, Voice, ForceReply, ReplyKeyboardMarkup
from pyrogram.errors import bad_request_400
from dateutil.relativedelta import relativedelta
from classes.errors.geo import PlaceNotFoundError
from classes.errors.holo_user import UserInvalidError, UserNotFoundError, LabelTooLongError, LabelSettingError
from classes.templates import DefaultApplicationTemp, DefaultSponsorshipTemp
from modules.database import col_tmp, col_users, col_applications, col_sponsorships, col_messages, col_spoilers
from modules.logging import logWrite
from modules.utils import configGet, create_tmp, download_tmp, find_location, locale, should_quote
class DefaultApplicationTemp(dict):
def __init__(self, user: int, reapply: bool = False):
super().__init__({})
self.dict = {
"user": user,
"type": "application",
"complete": False,
"sent": False,
"state": "fill",
"reapply": reapply,
"stage": 1,
"application": {
"1": None,
"2": None,
"3": None,
"4": None,
"5": None,
"6": None,
"7": None,
"8": None,
"9": None,
"10": None
}
}
class DefaultSponsorshipTemp(dict):
def __init__(self, user: int):
super().__init__({})
self.dict = {
"user": user,
"type": "sponsorship",
"complete": False,
"sent": False,
"state": "fill",
"stage": 1,
"sponsorship": {
"streamer": None,
"expires": datetime.fromtimestamp(0),
"proof": None,
"label": ""
}
}
class UserNotFoundError(Exception):
"""HoloUser could not find user with such an ID in database"""
def __init__(self, user, user_id):
self.user = user
self.user_id = user_id
super().__init__(f"User of type {type(self.user)} with id {self.user_id} was not found")
class UserInvalidError(Exception):
"""Provided to HoloUser object is not supported"""
def __init__(self, user):
self.user = user
super().__init__(f"Could not find HoloUser by using {type(self.user)} as an input type")
class LabelTooLongError(Exception):
def __init__(self, label: str) -> None:
self.label = label
super().__init__(f"Could not set label to '{label}' because it is {len(label)} characters long (16 is maximum)")
from modules.utils import configGet, find_location, locale, should_quote
class HoloUser():
"""This object represents a user of HoloChecker bot.
@@ -215,11 +156,11 @@ class HoloUser():
if photo is not None:
if isinstance(photo, Photo):
photo = photo.file_id
new_message = await origin.reply_photo(photo, caption=caption, quote=True)
new_message = await origin.reply_cached_media(photo, caption=caption, quote=True)
elif video is not None:
if isinstance(video, Video):
video = video.file_id
new_message = await origin.reply_video(video, caption=caption, quote=True)
new_message = await origin.reply_cached_media(video, caption=caption, quote=True)
elif file is not None:
if isinstance(file, Document):
file = file.file_id
@@ -227,7 +168,7 @@ class HoloUser():
elif animation is not None:
if isinstance(animation, Animation):
animation = animation.file_id
new_message = await origin.reply_animation(animation, caption=caption, quote=True)
new_message = await origin.reply_cached_media(animation, caption=caption, quote=True)
elif voice is not None:
if isinstance(voice, Voice):
voice = voice.file_id
@@ -240,11 +181,11 @@ class HoloUser():
if photo is not None:
if isinstance(photo, Photo):
photo = photo.file_id
new_message = await app.send_photo(self.id, photo, caption=caption)
new_message = await app.send_cached_media(self.id, photo, caption=caption)
elif video is not None:
if isinstance(video, Video):
video = video.file_id
new_message = await app.send_video(self.id, video, caption=caption)
new_message = await app.send_cached_media(self.id, video, caption=caption)
elif file is not None:
if isinstance(file, Document):
file = file.file_id
@@ -252,11 +193,11 @@ class HoloUser():
elif animation is not None:
if isinstance(animation, Animation):
animation = animation.file_id
new_message = await app.send_animation(self.id, animation, caption=caption)
new_message = await app.send_cached_media(self.id, animation, caption=caption)
elif voice is not None:
if isinstance(voice, Voice):
voice = voice.file_id
new_message = await app.send_voice(self.id, voice, caption=caption)
new_message = await app.send_cached_media(self.id, voice, caption=caption)
else:
new_message = await app.send_message(self.id, text)
@@ -266,9 +207,9 @@ class HoloUser():
# Report to admin and to sender about message sending failure
except Exception as exp:
logWrite(f"Exception {exp} happened as {context.from_user.id} tried to send message to {self.id}. Traceback:\n{print_exc()}")
logWrite(f"Exception {exp} happened as {context.from_user.id} tried to send message to {self.id}. Traceback:\n{format_exc()}")
try:
await app.send_message(configGet("owner"), locale("message_traceback", "message").format(context.from_user.id, self.id, exp, print_exc()))
await app.send_message(configGet("owner"), locale("message_traceback", "message").format(context.from_user.id, self.id, exp, format_exc()))
except bad_request_400.PeerIdInvalid:
logWrite(f"Could not notify admin about failure when sending message! Admin has never interacted with bot!")
await context.reply_text(locale("message_error", "message"), quote=should_quote(context))
@@ -288,10 +229,9 @@ class HoloUser():
if not await isAnAdmin(self.id):
await app.set_administrator_title(configGet("users", "groups"), self.id, label)
self.set("label", label)
except bad_request_400.UserCreator:
logWrite(f"Could not set {self.id}'s title to '{self.label}' because of bad_request_400.UserCreator")
except bad_request_400.ChatAdminRequired:
logWrite(f"Could not set {self.id}'s title to '{self.label}' because of bad_request_400.ChatAdminRequired")
except Exception as exp:
logWrite(f"Could not set {self.id}'s title to '{self.label}' due to {exp}")
raise LabelSettingError(exp, format_exc())
async def label_reset(self, chat: Chat) -> None:
"""Reset label in destination group
@@ -391,7 +331,6 @@ class HoloUser():
return
else:
print(f'Look: {((datetime.now() - input_dt).days)} > {(datetime.now() - datetime.now().replace(year=datetime.now().year - configGet("age_allowed"))).days}')
progress["application"][str(stage)] = input_dt
col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "application"}}, {"$set": {"application": progress["application"], "stage": progress["stage"]+1}})
await msg.reply_text(locale(f"question{stage+1}", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage+1}", "force_reply", locale=self.locale))))
@@ -412,7 +351,7 @@ class HoloUser():
except Exception as exp:
await msg.reply_text(locale("question3_error", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage}", "force_reply", locale=self.locale))))
try:
await app.send_message(configGet("owner"), locale("question3_traceback", "message", locale=self.locale).format(query, exp, print_exc()))
await app.send_message(configGet("owner"), locale("question3_traceback", "message", locale=self.locale).format(query, exp, format_exc()))
except bad_request_400.PeerIdInvalid:
logWrite(f"Could not notify admin about failure when sending message! Admin has never interacted with bot!")
return
@@ -483,12 +422,9 @@ class HoloUser():
* msg (`Message`): Message that should receive replies
"""
if col_tmp.find_one({"user": self.id, "type": "sponsorship"}) is not None:
progress = col_tmp.find_one({"user": self.id, "type": "sponsorship"})
progress = col_tmp.find_one({"user": self.id, "type": "sponsorship"})
if progress is None:
return
if progress is not None:
stage = progress["stage"]
@@ -522,7 +458,7 @@ class HoloUser():
elif stage == 3:
if photo is not None:
progress["sponsorship"]["proof"] = await download_tmp(app, photo.file_id)
progress["sponsorship"]["proof"] = photo.file_id
col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}}, {"$set": {"sponsorship": progress["sponsorship"], "stage": progress["stage"]+1}})
await msg.reply_text(locale(f"sponsor{stage+1}", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"sponsor{stage+1}", "force_reply", locale=self.locale))))
@@ -532,8 +468,8 @@ class HoloUser():
return
progress["sponsorship"]["label"] = query
col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}}, {"$set": {"sponsorship": progress["sponsorship"], "complete": True}})
await msg.reply_photo(
photo=create_tmp(progress["sponsorship"]["proof"], kind="image"),
await msg.reply_cached_media(
progress["sponsorship"]["proof"],
caption=locale("sponsor_confirm", "message", locale=self.locale).format(
progress["sponsorship"]["streamer"],
progress["sponsorship"]["expires"].strftime("%d.%m.%Y"),

46
classes/templates.py Normal file
View File

@@ -0,0 +1,46 @@
"""Templates for temporary application/sponsorship records"""
from datetime import datetime
class DefaultApplicationTemp(dict):
def __init__(self, user: int, reapply: bool = False):
super().__init__({})
self.dict = {
"user": user,
"type": "application",
"complete": False,
"sent": False,
"state": "fill",
"reapply": reapply,
"stage": 1,
"application": {
"1": None,
"2": None,
"3": None,
"4": None,
"5": None,
"6": None,
"7": None,
"8": None,
"9": None,
"10": None
}
}
class DefaultSponsorshipTemp(dict):
def __init__(self, user: int):
super().__init__({})
self.dict = {
"user": user,
"type": "sponsorship",
"complete": False,
"sent": False,
"state": "fill",
"stage": 1,
"sponsorship": {
"streamer": None,
"expires": datetime.fromtimestamp(0),
"proof": None,
"label": ""
}
}

View File

@@ -1,4 +1,5 @@
from os import getpid, makedirs
from time import time
from modules.utils import *
from modules.inline import *
from app import app
@@ -40,7 +41,6 @@ from modules.handlers.contact import *
from modules.handlers.group_join import *
from modules.handlers.voice import *
from modules.handlers.welcome import *
from modules.handlers.sponsorship import *
from modules.handlers.everything import *
from modules.scheduled import *
@@ -54,7 +54,16 @@ if __name__ == "__main__":
app.start()
try:
app.send_message(configGet("owner"), f"Starting up with pid `{pid}`")
if path.exists(path.join(configGet("cache", "locations"), "shutdown_time")):
downtime = relativedelta(datetime.now(), datetime.fromtimestamp(jsonLoad(path.join(configGet("cache", "locations"), "shutdown_time"))["timestamp"]))
if downtime.days >= 1:
app.send_message(configGet("owner"), locale("startup_downtime_days", "message").format(pid, downtime.days))
elif downtime.hours >= 1:
app.send_message(configGet("owner"), locale("startup_downtime_hours", "message").format(pid, downtime.hours))
else:
app.send_message(configGet("owner"), locale("startup_downtime_minutes", "message").format(pid, downtime.minutes))
else:
app.send_message(configGet("owner"), locale("startup", "message").format(pid))
except bad_request_400.PeerIdInvalid:
logWrite(f"Could not send startup message to bot owner. Perhaps user has not started the bot yet.")
@@ -63,10 +72,13 @@ if __name__ == "__main__":
idle()
try:
app.send_message(configGet("owner"), f"Shutting with pid `{pid}`")
app.send_message(configGet("owner"), locale("shutdown", "message").format(pid))
except bad_request_400.PeerIdInvalid:
logWrite(f"Could not send shutdown message to bot owner. Perhaps user has not started the bot yet.")
app.stop()
makedirs(configGet("cache", "locations"), exist_ok=True)
jsonSave({"timestamp": time()}, path.join(configGet("cache", "locations"), "shutdown_time"))
killProc(pid)

View File

@@ -38,7 +38,9 @@
"sponsor_got": "Отримано форму на спонсорство від `{0}`\n\nІм'я тг: `{1}`\nЮзернейм: @{2}\n\n**Дані форми:**\n{3}",
"shutdown": "Вимкнення бота з підом `{0}`",
"startup": "Запуск бота з підом `{0}`",
"startup_downtime": "Запуск бота з підом `{0}` (лежав {1})",
"startup_downtime_minutes": "Запуск бота з підом `{0}` (лежав {1} хв.)",
"startup_downtime_hours": "Запуск бота з підом `{0}` (лежав {1} год.)",
"startup_downtime_days": "Запуск бота з підом `{0}` (лежав {1} дн.)",
"approved": "Вітаємо! Твою анкету переглянули та підтвердили твоє право на вступ. Скористайся кнопкою під повідомленням щоб вступити до нашої лампової спільноти!",
"approved_joined": "Вітаємо! Твою анкету переглянули та підтвердили її правильність. Дякуємо за витрачений на заповнення час та гарного дня!",
"read_rules": "Будь ласка, прочитай ці правила перш ніж натискати на кнопку та приєднуватись до чату.",
@@ -90,7 +92,7 @@
"sponsorships_expires": "⚠️ **Нагадування**\nНадана платна підписка припинить діяти **за {0} д**. Будь ласка, оновіть дані про неї командою /sponsorship інакше роль буде втрачено!",
"sponsorships_expired": "⚠️ **Нагадування**\nТермін дії вказаної підписки сплив. Для повторного отримання ролі користуйся командою /sponsorship.",
"label_too_long": "Довжина назви ролі не повинна перевищувати 16 символів",
"finish_sponsorship": "❌ **Дія неможлива**\nПерш ніж заповнювати анкету, треба завершити заповнення форми спонсора.",
"finish_sponsorship": "❌ **Дія неможлива**\nПерш ніж заповнювати анкету, треба завершити заповнення форми спонсора або перервати його командою /cancel.",
"finish_application": "❌ **Дія неможлива**\nПерш ніж заповнювати форму спонсора, треба завершити заповнення анкети.",
"nearby_invalid": " **Місце не знайдено**\nЗа наданим запитом не знайдено місце з координатами. Спробуйте ще раз формулючи запит в стилі \"Чернівці\" або \"Київська область\".",
"nearby_error": "⚠️ **Сталась помилка**\n\nПомилка: `{0}`\n\nTraceback:\n```\n{1}\n```",
@@ -100,15 +102,18 @@
"identify_invalid_syntax": "Неправильний синтаксис!\nТреба: `/identify ID/NAME/USERNAME`",
"identify_not_found": "Не знайдено користувачів за запитом **{0}**",
"identify_success": "Користувач `{0}`\n\nІм'я: {1}\nЮзернейм: {2}\nЄ в чаті: {3}\nЄ адміном: {4}\nРоль: {5}\nНаявна анкета: {6}\nНаявне спонсорство: {7}",
"spoiler_started": "Розпочато створення спойлера. Надішліть щось",
"spoiler_started": "Розпочато створення спойлера. Будь ласка, оберіть категорію спойлера за допомогою клавіатури бота.",
"spoiler_unfinished": "У вас ще є незавершений спойлер. Надішліть /cancel щоб зупинити його створення",
"spoiler_cancel": "Створення спойлера було припинено",
"spoiler_empty": "Спойлер без опису",
"spoiler_described": "Спойлер: {0}",
"spoiler_empty": "Спойлер категорії \"{0}\" без опису",
"spoiler_described": "Спойлер категорії \"{0}\": {1}",
"spoiler_description_enter": "Добре, введіть бажаний опис спойлера",
"spoiler_using_description": "Встановлено опис спойлера: {0}",
"spoiler_send_description": "Майже впорались. Тепер треба надіслати коротенький опис спойлера, щоб люди розуміли що під ним варто очкувати. Надішли мінус (-) щоб пропустити цей крок.",
"spoiler_using_description": "Встановлено опис спойлера: {0}\n\nЗалишилось додати вміст самого спойлера. Бот приймає текстове повідомлення, фото, відео, файл а також гіф зображення (1 шт.)",
"spoiler_send_description": "Тепер треба надіслати коротенький опис спойлера, щоб люди розуміли що під ним варто очкувати. Надішли мінус (-) щоб пропустити цей крок.",
"spoiler_ready": "Успіх! Спойлер створено. Користуйтесь кнопкою нижче щоб надіслати його.",
"spoiler_incorrect_content": "Бот не підтримує такий контент. Будь ласка, надішли текст, фото, відео, файл або анімацію (гіф).",
"spoiler_incorrect_category": "Вказана категорія не є дійсною. Будь ласка, користуйся клавіатурою бота (кнопка біля 📎) для вибору категорії.",
"spoiler_in_progress": "❌ **Дія неможлива**\nПерш ніж починати нову дію, треба завершити створення спойлера або перервати його командою /cancel.",
"yes": "Так",
"no": "Ні",
"voice_message": [
@@ -132,6 +137,11 @@
"question_streamer": "Стрімер:",
"question_expires": "Підписка до:",
"question_label": "Хоче роль:"
},
"spoiler_categories": {
"nsfw": "NSFW контент",
"deanon": "Деанон холо-учасників",
"other": "Інше"
}
},
"keyboard": {
@@ -156,7 +166,7 @@
"Ні, повторно заповнити"
]
],
"spoiler_description": [
"spoiler_categories": [
[
"NSFW контент"
],
@@ -164,7 +174,7 @@
"Деанон холо-учасників"
],
[
"Інше (надішліть свій текст)"
"Інше"
]
]
},

View File

@@ -3,6 +3,7 @@ from app import app
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ForceReply, CallbackQuery
from pyrogram.client import Client
from pyrogram import filters
from classes.errors.holo_user import LabelSettingError
from classes.holo_user import HoloUser
from modules.utils import configGet, locale, logWrite, should_quote
from modules.database import col_tmp, col_sponsorships
@@ -67,7 +68,10 @@ async def callback_query_sponsor_yes(app: Client, clb: CallbackQuery):
}
)
await holo_user.label_set(configGet("users", "groups"), col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}})["sponsorship"]["label"])
try:
await holo_user.label_set(configGet("users", "groups"), col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}})["sponsorship"]["label"])
except LabelSettingError as exp:
await app.send_message(configGet("admin", "groups"), exp.__str__(), disable_notification=True)
edited_markup = [[InlineKeyboardButton(text=str(locale("accepted", "button")), callback_data="nothing")]]

View File

@@ -5,13 +5,14 @@ from pyrogram.enums.parse_mode import ParseMode
from pyrogram.types import Message
from pyrogram.errors import bad_request_400
from pyrogram.client import Client
from classes.holo_user import HoloUser, UserNotFoundError
from classes.errors.holo_user import UserNotFoundError
from classes.holo_user import HoloUser
from modules.utils import logWrite, locale, should_quote
from dateutil.relativedelta import relativedelta
from modules.database import col_applications
from modules import custom_filters
# Applications command =========================================================================================================
# Application command ==========================================================================================================
@app.on_message(custom_filters.enabled_applications & ~filters.scheduled & filters.command(["application"], prefixes=["/"]) & custom_filters.admin)
async def cmd_application(app: Client, msg: Message):
@@ -56,42 +57,6 @@ async def cmd_application(app: Client, msg: Message):
logWrite(f"User {msg.from_user.id} requested application of {holo_user.id}")
await msg.reply_text(locale("contact", "message", locale=msg.from_user).format(holo_user.id, "\n".join(application_content), application_status), parse_mode=ParseMode.MARKDOWN, quote=should_quote(msg))
# if (path.exists(f"{configGet('data', 'locations')}{sep}users{sep}{msg.command[1]}.json") and jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{msg.command[1]}.json")["approved"]):
# user_id = int(msg.command[1])
# else:
# list_of_users = []
# async for m in app.get_chat_members(configGet("users", "groups"), filter=ChatMembersFilter.SEARCH, query=msg.command[1]):
# list_of_users.append(m)
# user_id = list_of_users[0].user.id
# try:
# user_data = jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{user_id}.json")
# application = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")[str(user_id)]
# application_content = []
# i = 1
# for question in configGet("application", file=str(msg.from_user.id)):
# if i == 2:
# age = relativedelta(datetime.now(), datetime.strptime(application['application']['2'], '%d.%m.%Y'))
# application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {application['application']['2']} ({age.years} р.)")
# else:
# application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {application['application'][question]}")
# i += 1
# if user_data["sent"]:
# if user_data["approved"]:
# application_status = locale("application_status_accepted", "message").format((await app.get_users(application["approved_by"])).first_name, datetime.fromtimestamp(application["approval_date"]).strftime("%d.%m.%Y, %H:%M"))
# elif application["rejected"]:
# application_status = locale("application_status_rejected", "message").format((await app.get_users(application["rejected_by"])).first_name, datetime.fromtimestamp(application["refusal_date"]).strftime("%d.%m.%Y, %H:%M"))
# else:
# application_status = locale("application_status_on_hold", "message")
# else:
# if user_data["approved"]:
# application_status = locale("application_status_accepted", "message").format((await app.get_users(application["approved_by"])).first_name, datetime.fromtimestamp(application["approval_date"]).strftime("%d.%m.%Y, %H:%M"))
# elif application["rejected"]:
# application_status = locale("application_status_rejected", "message").format((await app.get_users(application["rejected_by"])).first_name, datetime.fromtimestamp(application["refusal_date"]).strftime("%d.%m.%Y, %H:%M"))
# else:
# application_status = locale("application_status_not_send", "message")
# logWrite(f"User {msg.from_user.id} requested application of {user_id}")
# await msg.reply_text(locale("contact", "message").format(str(user_id), "\n".join(application_content), application_status), quote=should_quote(msg))
except IndexError:
await msg.reply_text(locale("application_invalid_syntax", "message", locale=msg.from_user), quote=should_quote(msg))
# ==============================================================================================================================

View File

@@ -1,14 +1,16 @@
from app import app
from pyrogram import filters
from pyrogram.types import Message
from pyrogram.types import Message, ReplyKeyboardRemove
from pyrogram.client import Client
from modules.utils import should_quote, logWrite, locale
from modules.database import col_tmp, col_spoilers
from modules import custom_filters
# Cancel command ===============================================================================================================
@app.on_message((custom_filters.enabled_applications | custom_filters.enabled_sponsorships) & ~filters.scheduled & filters.command("cancel", prefixes=["/"]))
async def command_cancel(app: Client, msg: Message):
col_tmp.delete_many( {"user": msg.from_user.id} )
col_spoilers.delete_many( {"user": msg.from_user.id, "completed": False} )
await msg.reply_text(locale("cancel", "message", locale=msg.from_user), quote=should_quote(msg))
await msg.reply_text(locale("cancel", "message", locale=msg.from_user), quote=should_quote(msg), reply_markup=ReplyKeyboardRemove())
logWrite(f"Cancelling all ongoing tmp operations for {msg.from_user.id}")
# ==============================================================================================================================

View File

@@ -5,12 +5,14 @@ from pyrogram.types import Message
from pyrogram.client import Client
from pyrogram.errors import bad_request_400
from pyrogram.enums.chat_action import ChatAction
from classes.holo_user import HoloUser, UserNotFoundError, UserInvalidError
from classes.errors.holo_user import UserNotFoundError, UserInvalidError
from classes.holo_user import HoloUser
from modules.utils import jsonLoad, should_quote, logWrite, locale, download_tmp, create_tmp, find_user
from modules import custom_filters
# Identify command =============================================================================================================
@app.on_message((custom_filters.enabled_applications | custom_filters.enabled_sponsorships) & ~filters.scheduled & filters.command("identify", prefixes=["/"]) & custom_filters.admin)
async def command_identify(app: Client, msg: Message):
async def cmd_identify(app: Client, msg: Message):
if len(msg.command) != 2:
await msg.reply_text(locale("identify_invalid_syntax", "message", locale=msg.from_user))
@@ -61,3 +63,4 @@ async def command_identify(app: Client, msg: Message):
)
logWrite(f"User {msg.from_user.id} identified user {holo_user.id}")
# ==============================================================================================================================

View File

@@ -2,10 +2,12 @@ from app import app
from pyrogram import filters
from pyrogram.types import Message
from pyrogram.client import Client
from modules.utils import locale, should_quote, find_user
from classes.holo_user import HoloUser, LabelTooLongError
from modules.utils import configGet, locale, should_quote, find_user
from classes.errors.holo_user import LabelTooLongError, LabelSettingError
from classes.holo_user import HoloUser
from modules import custom_filters
# Label command ================================================================================================================
@app.on_message(custom_filters.enabled_applications & ~filters.scheduled & filters.command(["label"], prefixes=["/"]) & custom_filters.admin)
async def cmd_label(app: Client, msg: Message):
@@ -31,7 +33,11 @@ async def cmd_label(app: Client, msg: Message):
except LabelTooLongError:
await msg.reply_text(locale("label_too_long", "message"))
return
except LabelSettingError as exp:
await app.send_message(configGet("admin", "groups"), exp.__str__(), disable_notification=True)
return
await msg.reply_text(f"Setting **{target.id}**'s label to **{label}**...", quote=should_quote(msg))
else:
await msg.reply_text(f"User not found")
# ==============================================================================================================================

View File

@@ -2,8 +2,9 @@ from app import app
from pyrogram import filters
from pyrogram.types import Message
from pyrogram.client import Client
from classes.errors.holo_user import UserInvalidError
from classes.holo_user import HoloUser
from modules.utils import logWrite, locale, should_quote
from modules.utils import logWrite, locale, should_quote, find_user
from modules import custom_filters
# Message command ==============================================================================================================
@@ -14,15 +15,15 @@ async def cmd_message(app: Client, msg: Message):
try:
destination = HoloUser(int(msg.command[1]))
except ValueError:
destination = HoloUser(msg.command[1])
except (ValueError, UserInvalidError):
destination = HoloUser(await find_user(app, query=msg.command[1]))
if ((msg.text is not None) and (len(msg.text.split()) > 2)):
await destination.message(context=msg, text=" ".join(msg.text.split()[2:]), caption=msg.caption, photo=msg.photo, video=msg.video, file=msg.document, adm_context=True)
await destination.message(context=msg, text=" ".join(msg.text.split()[2:]), caption=msg.caption, photo=msg.photo, video=msg.video, file=msg.document, voice=msg.voice, animation=msg.animation, adm_context=True)
elif ((msg.caption is not None) and (len(msg.caption.split()) > 2)):
await destination.message(context=msg, text=msg.text, caption=" ".join(msg.caption.split()[2:]), photo=msg.photo, video=msg.video, file=msg.document, adm_context=True)
await destination.message(context=msg, text=msg.text, caption=" ".join(msg.caption.split()[2:]), photo=msg.photo, video=msg.video, file=msg.document, voice=msg.voice, animation=msg.animation, adm_context=True)
else:
await destination.message(context=msg, text=None, caption=None, photo=msg.photo, video=msg.video, file=msg.document, adm_context=True)
await destination.message(context=msg, text=None, caption=None, photo=msg.photo, video=msg.video, file=msg.document, voice=msg.voice, animation=msg.animation, adm_context=True)
except IndexError:
await msg.reply_text(locale("message_invalid_syntax", "message", locale=msg.from_user), quote=should_quote(msg))

View File

@@ -38,7 +38,6 @@ async def cmd_nearby(app: Client, msg: Message):
# Find all users registered in the area provided
output = []
applications_nearby = col_applications.find( {"application.3.location": { "$nearSphere": {"$geometry": {"type": "Point", "coordinates": [location[0], location[1]]}, "$maxDistance": configGet("search_radius")*1000} } } )
# {"application": {"3": {"location": {"$near": { "$geometry": { "type": "Point", "coordinates": location }, "$maxDistance": 30000 }} } } } )
for entry in applications_nearby:
if not entry["user"] == msg.from_user.id:
@@ -56,18 +55,4 @@ async def cmd_nearby(app: Client, msg: Message):
await msg.reply_text(locale("nearby_result", "message", locale=holo_user).format("\n".join(output)), quote=should_quote(msg))
else:
await msg.reply_text(locale("nearby_empty", "message", locale=holo_user), quote=should_quote(msg))
# if not path.exists(f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json"):
# jsonSave(jsonLoad(f"{configGet('data', 'locations')}{sep}sponsor_default.json"), f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json")
# sponsor = jsonLoad(f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json")
# if sponsor["approved"]:
# if sponsor["expires"] is not None:
# if datetime.strptime(sponsor["expires"], "%d.%m.%Y") > datetime.now():
# await msg.reply_text(f"You have an active sub til **{sponsor['expires']}**.")
# else:
# await msg.reply_text(f"Your sub expired {int((datetime.now()-datetime.strptime(sponsor['expires'], '%d.%m.%Y')).days)} days ago.")
# elif sponsor["approved"]:
# await msg.reply_text(f"Your sub expiration date is not valid.")
# else:
# await msg.reply_text(f"You have no active subscription.")
# ==============================================================================================================================

View File

@@ -15,7 +15,7 @@ async def cmd_reapply(app: Client, msg: Message):
holo_user = HoloUser(msg.from_user)
# Check if user has approved/rejected tmp application
if (holo_user.application_state()[0] in ["approved", "rejected"]) or (holo_user.application_state()[0] == "none"):
if ((holo_user.application_state()[0] in ["approved", "rejected"]) or (holo_user.application_state()[0] == "none")) and holo_user.spoiler_state() is False:
# Check if user's tmp application is already completed or even sent
if ((holo_user.application_state()[1] is True) and (not col_tmp.find_one({"user": holo_user.id, "type": "application"})["sent"])) or (holo_user.application_state()[0] == "none"):
@@ -51,6 +51,10 @@ async def cmd_reapply(app: Client, msg: Message):
]
]))
elif holo_user.spoiler_state() is True:
await msg.reply_text(locale("spoiler_in_progress", "message", locale=holo_user))
else:
if (holo_user.application_state()[0] == "fill") and (col_tmp.find_one({"user": holo_user.id, "type": "application"})["sent"] is True):

View File

@@ -1,21 +1,24 @@
from app import app
from os import getpid
from os import getpid, makedirs, path
from sys import exit
from time import time
from pyrogram import filters
from pyrogram.types import Message
from pyrogram.client import Client
from modules.utils import locale, logWrite, should_quote
from modules.utils import configGet, jsonSave, locale, logWrite, should_quote
from modules.scheduled import scheduler
from modules import custom_filters
pid = getpid()
# Shutdown command =============================================================================================================
# Reboot command ===============================================================================================================
@app.on_message(custom_filters.enabled_general & ~filters.scheduled & filters.private & filters.command(["kill", "die", "reboot"], prefixes=["/"]) & custom_filters.admin)
async def cmd_kill(app: Client, msg: Message):
logWrite(f"Shutting down bot with pid {pid}")
await msg.reply_text(locale("shutdown", "message", locale=msg.from_user).format(pid), quote=should_quote(msg))
scheduler.shutdown()
makedirs(configGet("cache", "locations"), exist_ok=True)
jsonSave({"timestamp": time()}, path.join(configGet("cache", "locations"), "shutdown_time"))
exit()
# ==============================================================================================================================

View File

@@ -9,9 +9,9 @@ from modules import custom_filters
pid = getpid()
# Shutdown command =============================================================================================================
# Reset commands command =======================================================================================================
@app.on_message(custom_filters.enabled_general & ~filters.scheduled & filters.private & filters.command(["resetcommands"], prefixes=["/"]) & custom_filters.admin)
async def cmd_kill(app: Client, msg: Message):
async def cmd_resetcommands(app: Client, msg: Message):
if msg.from_user.id == configGet("owner"):

View File

@@ -1,8 +1,9 @@
from app import app
from pyrogram import filters
from pyrogram.types import Message, ForceReply
from pyrogram.types import Message, ReplyKeyboardMarkup
from pyrogram.client import Client
from classes.holo_user import HoloUser, UserInvalidError, UserNotFoundError
from classes.errors.holo_user import UserNotFoundError, UserInvalidError
from classes.holo_user import HoloUser
from modules.logging import logWrite
from modules.utils import locale
from modules.database import col_spoilers
@@ -25,15 +26,18 @@ async def cmd_spoiler(app: Client, msg: Message):
{
"user": msg.from_user.id,
"completed": False,
"category": None,
"description": None,
"photo": None,
"video": None,
"animation": None,
"document": None,
"caption": None,
"text": None
}
)
await msg.reply_text(locale("spoiler_started", "message", locale=msg.from_user), reply_markup=ForceReply(placeholder=locale("spoiler_content", "force_reply", locale=msg.from_user)))
await msg.reply_text(locale("spoiler_started", "message", locale=msg.from_user), reply_markup=ReplyKeyboardMarkup(locale("spoiler_categories", "keyboard"), resize_keyboard=True, one_time_keyboard=True))
logWrite(f"User {msg.from_user.id} started creating new spoiler")
else:

View File

@@ -10,9 +10,13 @@ from modules.database import col_applications
# Sponsorship command ==========================================================================================================
@app.on_message(custom_filters.enabled_sponsorships & ~filters.scheduled & filters.command(["sponsorship"], prefixes=["/"]) & (custom_filters.allowed | custom_filters.admin))
async def cmd_sponsorship(app: Client, msg: Message):
if HoloUser(msg.from_user).application_state()[0] == "fill":
holo_user = HoloUser(msg.from_user)
if holo_user.application_state()[0] == "fill":
await msg.reply_text(locale("finish_application", "message", locale=msg.from_user), quote=should_quote(msg))
return
if holo_user.spoiler_state() is True:
await msg.reply_text(locale("spoiler_in_progress", "message", locale=holo_user))
return
await msg.reply_text(locale("sponsorship_apply", "message", locale=msg.from_user), reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(text=str(locale("sponsor_apply", "button", locale=msg.from_user)), callback_data=f"sponsor_apply_{msg.from_user.id}")]]), quote=should_quote(msg))
# else:
# await msg.reply_text(locale("sponsorship_application_empty", "message"))

View File

@@ -33,11 +33,13 @@ async def cmd_start(app: Client, msg: Message):
try:
spoiler = col_spoilers.find_one( {"_id": ObjectId(msg.command[1])} )
if spoiler["photo"] is not None:
await msg.reply_photo(spoiler["photo"])
await msg.reply_document(spoiler["photo"], caption=spoiler["caption"])
if spoiler["video"] is not None:
await msg.reply_video(spoiler["video"])
await msg.reply_cached_media(spoiler["video"], caption=spoiler["caption"])
if spoiler["animation"] is not None:
await msg.reply_animation(spoiler["animation"])
await msg.reply_cached_media(spoiler["animation"], caption=spoiler["caption"])
if spoiler["document"] is not None:
await msg.reply_document(spoiler["document"], caption=spoiler["caption"])
if spoiler["text"] is not None:
await msg.reply_text(spoiler["text"])
except InvalidId:

View File

@@ -1,6 +1,4 @@
from os import remove, sep
from typing import Literal
from uuid import uuid1
from dateutil.relativedelta import relativedelta
from datetime import datetime
from app import app
@@ -93,9 +91,6 @@ async def confirm_yes(app: Client, msg: Message, kind: Literal["application", "s
return
# configSet(["sent"], True, file=str(holo_user.id))
# configSet(["confirmed"], True, file=str(holo_user.id))
if configGet("enabled", "features", "sponsorships") is True:
if (kind == "sponsorship") or ((holo_user.sponsorship_state()[0] == "fill") and (holo_user.sponsorship_state()[1] is True)):
@@ -118,13 +113,11 @@ async def confirm_yes(app: Client, msg: Message, kind: Literal["application", "s
if question == "expires":
sponsorship_content.append(f"{locale(f'question_{question}', 'message', 'sponsor_titles')} {tmp_sponsorship['sponsorship'][question].strftime('%d.%m.%Y')}")
elif question == "proof":
filename = uuid1()
with open(f"tmp{sep}{filename}.jpg", "wb") as f:
f.write(tmp_sponsorship['sponsorship']['proof'])
continue
else:
sponsorship_content.append(f"{locale(f'question_{question}', 'message', 'sponsor_titles')} {tmp_sponsorship['sponsorship'][question]}")
await app.send_photo(chat_id=configGet("admin", "groups"), photo=f"tmp{sep}{filename}.jpg", caption=(locale("sponsor_got", "message")).format(str(holo_user.id), msg.from_user.first_name, msg.from_user.username, "\n".join(sponsorship_content)), parse_mode=ParseMode.MARKDOWN, reply_markup=InlineKeyboardMarkup(
await app.send_cached_media(chat_id=configGet("admin", "groups"), photo=tmp_sponsorship["sponsorship"]["proof"], caption=(locale("sponsor_got", "message")).format(str(holo_user.id), msg.from_user.first_name, msg.from_user.username, "\n".join(sponsorship_content)), parse_mode=ParseMode.MARKDOWN, reply_markup=InlineKeyboardMarkup(
[
[
InlineKeyboardButton(text=str(locale("sponsor_yes", "button")), callback_data=f"sponsor_yes_{holo_user.id}")
@@ -136,7 +129,7 @@ async def confirm_yes(app: Client, msg: Message, kind: Literal["application", "s
)
)
remove(f"tmp{sep}{filename}.jpg")
# remove(f"tmp{sep}{filename}.jpg")
logWrite(f"User {holo_user.id} sent his sponsorship application and it will now be reviewed")

View File

@@ -1,12 +1,12 @@
from traceback import print_exc
from app import app, isAnAdmin
import asyncio
from pyrogram import filters
from pyrogram.types import Message, ReplyKeyboardMarkup, ReplyKeyboardRemove, ForceReply, InlineKeyboardMarkup, InlineKeyboardButton
from pyrogram.types import Message, ForceReply, InlineKeyboardMarkup, InlineKeyboardButton
from pyrogram.client import Client
from classes.holo_user import HoloUser
from modules.utils import configGet, logWrite, locale, all_locales
from modules.database import col_messages, col_spoilers
from bson import ObjectId
async def message_involved(msg: Message) -> bool:
message = col_messages.find_one({"destination.id": msg.reply_to_message.id, "destination.chat": msg.reply_to_message.chat.id})
@@ -43,13 +43,12 @@ async def any_stage(app: Client, msg: Message):
photo=msg.photo,
video=msg.video,
file=msg.document,
animation=msg.animation,
voice=msg.voice,
adm_origin=await isAnAdmin(context_message.from_user.id),
adm_context=await isAnAdmin(msg.from_user.id)
)
# await msg.reply_text(locale("message_sent", "message"), quote=should_quote(msg))
# col_messages.insert_one({"origin": {"chat": msg.chat.id, "id": msg.id}, "destination": {"chat": new_message.chat.id, "id": new_message.id}})
return
if msg.text is not None:
@@ -58,7 +57,11 @@ async def any_stage(app: Client, msg: Message):
await holo_user.application_next(msg.text, msg=msg)
if configGet("enabled", "features", "sponsorships") is True:
await holo_user.sponsorship_next(msg.text, msg=msg)
await holo_user.sponsorship_next(msg.text, msg)
if msg.photo is not None:
await holo_user.sponsorship_next(msg.text, msg=msg, photo=msg.photo)
if holo_user.application_state()[0] != "fill" and holo_user.sponsorship_state()[0] != "fill":
@@ -67,108 +70,87 @@ async def any_stage(app: Client, msg: Message):
if spoiler is None:
return
if msg.photo is not None:
col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"photo": msg.photo.file_id}} )
await msg.reply_text(locale("spoiler_send_description", "message", locale=msg.from_user), reply_markup=ReplyKeyboardMarkup(locale("spoiler_description", "keyboard"), resize_keyboard=True, one_time_keyboard=True, placeholder=locale("spoiler_description", "force_reply", locale=msg.from_user)))
logWrite(f"Adding photo with id {msg.photo.file_id} to {msg.from_user.id}'s spoiler")
if spoiler["category"] is None:
found = False
# Find category in all locales
for lc in all_locales("spoiler_categories", "message"):
for key in lc:
if lc[key] == msg.text:
found = True
category = key
if found is False:
await msg.reply_text(locale("spoiler_incorrect_category", "message", locale=msg.from_user))
return
col_spoilers.find_one_and_update( {"_id": spoiler["_id"]}, {"$set": {"category": category}} )
await msg.reply_text(locale("spoiler_send_description", "message", locale=msg.from_user), reply_markup=ForceReply(placeholder=locale("spoiler_description", "force_reply", locale=msg.from_user)))
return
if spoiler["description"] is None and (spoiler["photo"] is None and spoiler["video"] is None and spoiler["animation"] is None and spoiler["text"] is None):
# for lc in all_locales("spoiler_description", "keyboard"):
# if msg.text == lc[-1][0]:
# await msg.reply_text(locale("spoiler_description_enter", "message", locale=msg.from_user), reply_markup=ForceReply(placeholder=locale("spoiler_description", "force_reply", locale=msg.from_user)))
# return
if msg.text != "-":
col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"description": msg.text}} )
else:
col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"description": ""}} )
logWrite(f"Adding description '{msg.text}' to {msg.from_user.id}'s spoiler")
await msg.reply_text(locale("spoiler_using_description", "message", locale=msg.from_user).format(msg.text), reply_markup=ForceReply(placeholder=locale("spoiler_content", "force_reply", locale=msg.from_user)))
return
ready = False
if msg.photo is not None:
col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"photo": msg.photo.file_id, "caption": msg.caption, "completed": True}} )
logWrite(f"Adding photo with id {msg.photo.file_id} to {msg.from_user.id}'s spoiler")
ready = True
if msg.video is not None:
col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"video": msg.video.file_id}} )
await msg.reply_text(locale("spoiler_send_description", "message", locale=msg.from_user), reply_markup=ReplyKeyboardMarkup(locale("spoiler_description", "keyboard"), resize_keyboard=True, one_time_keyboard=True, placeholder=locale("spoiler_description", "force_reply", locale=msg.from_user)))
col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"video": msg.video.file_id, "caption": msg.caption, "completed": True}} )
logWrite(f"Adding video with id {msg.video.file_id} to {msg.from_user.id}'s spoiler")
return
ready = True
if msg.animation is not None:
col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"animation": msg.animation.file_id}} )
await msg.reply_text(locale("spoiler_send_description", "message", locale=msg.from_user), reply_markup=ReplyKeyboardMarkup(locale("spoiler_description", "keyboard"), resize_keyboard=True, one_time_keyboard=True, placeholder=locale("spoiler_description", "force_reply", locale=msg.from_user)))
col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"animation": msg.animation.file_id, "caption": msg.caption, "completed": True}} )
logWrite(f"Adding animation with id {msg.animation.file_id} to {msg.from_user.id}'s spoiler")
return
ready = True
if spoiler["photo"] is None and spoiler["video"] is None and spoiler["animation"] is None and spoiler["text"] is None:
col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"text": msg.text}} )
await msg.reply_text(locale("spoiler_send_description", "message", locale=msg.from_user), reply_markup=ReplyKeyboardMarkup(locale("spoiler_description", "keyboard"), resize_keyboard=True, one_time_keyboard=True, placeholder=locale("spoiler_description", "force_reply", locale=msg.from_user)))
logWrite(f"Adding text '{msg.text}' to {msg.from_user.id}'s spoiler")
if msg.document is not None:
col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"document": msg.document.file_id, "caption": msg.caption, "completed": True}} )
logWrite(f"Adding document with id {msg.document.file_id} to {msg.from_user.id}'s spoiler")
ready = True
if spoiler["photo"] is None and spoiler["video"] is None and spoiler["animation"] is None and spoiler["document"] is None and spoiler["text"] is None:
if msg.text is not None:
col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"text": msg.text, "completed": True}} )
logWrite(f"Adding text '{msg.text}' to {msg.from_user.id}'s spoiler")
ready = True
if ready is True:
await msg.reply_text(locale("spoiler_ready", "message", locale=msg.from_user), reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(locale("spoiler_send", "button", locale=msg.from_user), switch_inline_query=f"spoiler:{spoiler['_id'].__str__()}")]]))
else:
for lc in all_locales("spoiler_description", "keyboard"):
if msg.text == lc[-1][0]:
await msg.reply_text(locale("spoiler_description_enter", "message", locale=msg.from_user), reply_markup=ForceReply(placeholder=locale("spoiler_description", "force_reply", locale=msg.from_user)))
return
if msg.text != "-":
col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"description": msg.text, "completed": True}} )
else:
col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"description": None, "completed": True}} )
logWrite(f"Adding description '{msg.text}' to {msg.from_user.id}'s spoiler")
await msg.reply_text(locale("spoiler_using_description", "message", locale=msg.from_user).format(msg.text), reply_markup=ReplyKeyboardRemove())
await msg.reply_text(locale("spoiler_ready", "message", locale=msg.from_user), quote=False, reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(locale("spoiler_send", "button", locale=msg.from_user), switch_inline_query=f"spoiler:{spoiler['_id'].__str__()}")]]))
await msg.reply_text(locale("spoiler_incorrect_content", "message", locale=msg.from_user))
# user_stage = configGet("stage", file=str(msg.from_user.id))
# if user_stage == 1:
# await msg.reply_text(locale(f"question{user_stage+1}", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{user_stage+1}", "force_reply"))))
# logWrite(f"User {msg.from_user.id} completed stage {user_stage} of application")
# configSet(["application", str(user_stage)], str(msg.text), file=str(msg.from_user.id))
# configSet(["stage"], user_stage+1, file=str(msg.from_user.id))
# elif user_stage == 2:
# try:
# configSet(["application", str(user_stage)], str(msg.text), file=str(msg.from_user.id))
# input_dt = datetime.strptime(msg.text, "%d.%m.%Y")
# if datetime.now() <= input_dt:
# logWrite(f"User {msg.from_user.id} failed stage {user_stage} due to joking")
# await msg.reply_text(locale("question2_joke", "message"), reply_markup=ForceReply(placeholder=str(locale("question2", "force_reply"))))
# elif ((datetime.now() - input_dt).days) < ((datetime.now() - datetime.now().replace(year=datetime.now().year - configGet("age_allowed"))).days):
# logWrite(f"User {msg.from_user.id} failed stage {user_stage} due to being underage")
# await msg.reply_text(locale("question2_underage", "message").format(str(configGet("age_allowed"))), reply_markup=ForceReply(placeholder=str(locale("question2", "force_reply"))))
# else:
# logWrite(f"User {msg.from_user.id} completed stage {user_stage} of application")
# await msg.reply_text(locale(f"question{user_stage+1}", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{user_stage+1}", "force_reply"))))
# configSet(["stage"], user_stage+1, file=str(msg.from_user.id))
# except ValueError:
# logWrite(f"User {msg.from_user.id} failed stage {user_stage} due to sending invalid date format")
# await msg.reply_text(locale(f"question2_invalid", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{user_stage}", "force_reply"))))
# else:
# if user_stage <= 9:
# logWrite(f"User {msg.from_user.id} completed stage {user_stage} of application")
# await msg.reply_text(locale(f"question{user_stage+1}", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{user_stage+1}", "force_reply"))))
# configSet(["application", str(user_stage)], str(msg.text), file=str(msg.from_user.id))
# configSet(["stage"], user_stage+1, file=str(msg.from_user.id))
# else:
# if not configGet("sent", file=str(msg.from_user.id)):
# if not configGet("confirmed", file=str(msg.from_user.id)):
# configSet(["application", str(user_stage)], str(msg.text), file=str(msg.from_user.id))
# application_content = []
# i = 1
# for question in configGet("application", file=str(msg.from_user.id)):
# application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {configGet('application', file=str(msg.from_user.id))[question]}")
# i += 1
# await msg.reply_text(locale("confirm", "message").format("\n".join(application_content)), reply_markup=ReplyKeyboardMarkup(locale("confirm", "keyboard"), resize_keyboard=True))
# #configSet("sent", True, file=str(msg.from_user.id))
# #configSet("application_date", int(time()), file=str(msg.from_user.id))
# else:
# if not configGet("approved", file=str(msg.from_user.id)) and not configGet("rejected", file=str(msg.from_user.id)):
# await msg.reply_text(locale("already_sent", "message"))
# else:
# if not configGet("approved", file=str(msg.from_user.id)) and not configGet("rejected", file=str(msg.from_user.id)):
# await msg.reply_text(locale("already_sent", "message"))
@app.on_message(~ filters.scheduled & filters.group)
async def message_in_group(app: Client, msg: Message):
if (msg.chat is not None) and (msg.via_bot is not None):
if (msg.via_bot.id == (await app.get_me()).id) and (msg.chat.id == configGet("users", "groups")):
if msg.text.startswith(locale("spoiler_described", "message").split()[0]) or msg.text.startswith(locale("spoiler_empty", "message").split()[0]):
logWrite(f"User {msg.from_user.id} sent spoiler to user's group")
try:
await msg.forward(configGet("users", "groups"), disable_notification=True)
except:
pass
logWrite("Forwarding spoiler to admin's group")
await msg.copy(configGet("admin", "groups"), disable_notification=True)
except Exception as exp:
logWrite(f"Could not forward spoiler to admin's group due to '{exp}': {print_exc()}")
return
if configGet("remove_application_time") > 0:
logWrite(f"User {msg.from_user.id} requested application in destination group, removing in {configGet('remove_application_time')} minutes")

View File

@@ -1,16 +0,0 @@
from app import app
from pyrogram import filters
from pyrogram.types import Message
from pyrogram.client import Client
from classes.holo_user import HoloUser
from modules import custom_filters
@app.on_message(custom_filters.enabled_sponsorships & custom_filters.filling_sponsorship & ~filters.scheduled & filters.private)
async def sponsor_proof(app: Client, msg: Message):
if msg.via_bot is None:
holo_user = HoloUser(msg.from_user)
if msg.photo is not None:
await holo_user.sponsorship_next(msg.text, msg=msg, photo=msg.photo)

View File

@@ -31,8 +31,6 @@ async def welcome_pass(app: Client, msg: Message, once_again: bool = True) -> No
logWrite(f"User {msg.from_user.id} confirmed starting the application")
await msg.reply_text(locale("question1", "message", locale=msg.from_user), reply_markup=ForceReply(placeholder=locale("question1", "force_reply", locale=msg.from_user)))
# configSet(["stage"], 1, file=str(msg.from_user.id))
# configSet(["sent"], False, file=str(msg.from_user.id))
welcome_2 = []
for pattern in all_locales("welcome", "keyboard"):

View File

@@ -9,7 +9,8 @@ from pyrogram.client import Client
from pyrogram.enums.chat_type import ChatType
from pyrogram.enums.chat_members_filter import ChatMembersFilter
from dateutil.relativedelta import relativedelta
from classes.holo_user import HoloUser, UserInvalidError, UserNotFoundError
from classes.errors.holo_user import UserNotFoundError, UserInvalidError
from classes.holo_user import HoloUser
from modules.utils import configGet, locale
from modules.database import col_applications, col_spoilers
from bson.objectid import ObjectId
@@ -28,7 +29,7 @@ async def inline_answer(client: Client, inline_query: InlineQuery):
if spoil is not None:
desc = locale("spoiler_empty", "message", locale=inline_query.from_user) if spoil["description"] is None else locale("spoiler_described", "message", locale=inline_query.from_user).format(spoil["description"])
desc = locale("spoiler_empty", "message", locale=inline_query.from_user).format(locale(spoil["category"], "message", "spoiler_categories")) if spoil["description"] == "" else locale("spoiler_described", "message", locale=inline_query.from_user).format(locale(spoil["category"], "message", "spoiler_categories"), spoil["description"])
results = [
InlineQueryResultArticle(

View File

@@ -2,9 +2,9 @@ APScheduler==3.9.1.post1
fastapi==0.88.0
psutil==5.9.4
pymongo==4.3.3
Pyrogram==2.0.69
Pyrogram~=2.0.93
requests==2.28.1
tgcrypto==1.2.5
python_dateutil==2.8.2
starlette==0.22.0
starlette==0.23.0
ujson==5.6.0

View File

@@ -3,10 +3,13 @@
"required": [
"user",
"completed",
"category",
"description",
"photo",
"video",
"animation",
"document",
"caption",
"text"
],
"properties": {
@@ -18,6 +21,11 @@
"bsonType": "bool",
"description": "Whether spoiler is a completed one"
},
"category": {
"bsonType": ["string", "null"],
"enum": ["nsfw", "deanon", "other"],
"description": "Spoiler's category"
},
"description": {
"bsonType": ["string", "null"],
"description": "Spoiler's description"
@@ -34,6 +42,14 @@
"bsonType": ["string", "null"],
"description": "Spoilered animation/GIF"
},
"document": {
"bsonType": ["string", "null"],
"description": "Spoilered document/file"
},
"caption": {
"bsonType": ["string", "null"],
"description": "Spoilered caption for media"
},
"text": {
"bsonType": ["string", "null"],
"description": "Spoilered text"

View File

@@ -33,7 +33,7 @@
"bsonType": "date"
},
"sponsorship.proof": {
"bsonType": "binData"
"bsonType": "string"
},
"sponsorship.label": {
"bsonType": "string"